]> https://gitweb.dealii.org/ - dealii-svn.git/commitdiff
Import UMFPACK 4.3
authorwolf <wolf@0785d39b-7218-0410-832d-ea1e28bc413d>
Fri, 20 Aug 2004 16:31:03 +0000 (16:31 +0000)
committerwolf <wolf@0785d39b-7218-0410-832d-ea1e28bc413d>
Fri, 20 Aug 2004 16:31:03 +0000 (16:31 +0000)
git-svn-id: https://svn.dealii.org/trunk@9557 0785d39b-7218-0410-832d-ea1e28bc413d

239 files changed:
deal.II/contrib/umfpack/AMD/Demo/Makefile [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Demo/amd_demo.c [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Demo/amd_demo.out [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Demo/amd_demo2.c [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Demo/amd_demo2.out [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Demo/amd_f77cross.f [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Demo/amd_f77cross.out [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Demo/amd_f77demo.f [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Demo/amd_f77demo.out [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Demo/amd_f77simple.f [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Demo/amd_f77simple.out [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Demo/amd_f77wrapper.c [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Demo/amd_simple.c [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Demo/amd_simple.out [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Doc/AMD_UserGuide.bib [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Doc/AMD_UserGuide.pdf [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Doc/AMD_UserGuide.tex [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Doc/ChangeLog [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Doc/License [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Doc/Makefile [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Include/amd.h [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/MATLAB/Contents.m [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/MATLAB/GNUmakefile [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/MATLAB/Makefile [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/MATLAB/amd.m [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/MATLAB/amd_demo.m [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/MATLAB/amd_demo.m.out [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/MATLAB/amd_make.m [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/MATLAB/amd_mex.c [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/MATLAB/can_24.mat [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/README [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Source/Makefile [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Source/amd.f [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Source/amd_1.c [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Source/amd_2.c [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Source/amd_aat.c [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Source/amd_control.c [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Source/amd_defaults.c [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Source/amd_dump.c [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Source/amd_info.c [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Source/amd_internal.h [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Source/amd_order.c [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Source/amd_post_tree.c [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Source/amd_postorder.c [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Source/amd_preprocess.c [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Source/amd_valid.c [new file with mode: 0644]
deal.II/contrib/umfpack/AMD/Source/amdbar.f [new file with mode: 0644]
deal.II/contrib/umfpack/Makefile [new file with mode: 0644]
deal.II/contrib/umfpack/README [new file with mode: 0644]
deal.II/contrib/umfpack/README.deal.II [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Doc/ChangeLog [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Doc/License [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Doc/Makefile [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Doc/QuickStart.pdf [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Doc/QuickStart.tex [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.bib [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.pdf [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.sed1 [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.sed2 [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.stex [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_col_to_triplet.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_defaults.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_free_numeric.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_free_symbolic.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_get_lunz.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_get_numeric.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_get_symbolic.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_load_numeric.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_load_symbolic.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_numeric.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_qsymbolic.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_control.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_info.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_matrix.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_numeric.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_perm.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_status.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_symbolic.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_triplet.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_vector.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_save_numeric.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_save_symbolic.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_scale.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_solve.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_symbolic.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_tictoc.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_timer.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_transpose.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_triplet_to_col.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Include/umfpack_wsolve.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/MATLAB/Contents.m [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/MATLAB/GNUmakefile [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/MATLAB/Makefile [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/MATLAB/lu_normest.m [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/MATLAB/luflop.m [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/MATLAB/luflopmex.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack.m [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_btf.m [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_demo.m [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_demo.m.out [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_details.m [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_make.m [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_report.m [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_simple.m [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_simple.m.out [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_solve.m [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpackmex.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/MATLAB/west0067.mat [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/README [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/Makefile [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_2by2.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_2by2.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_analyze.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_analyze.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_apply_order.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_apply_order.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_assemble.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_assemble.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_blas3_update.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_blas3_update.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_build_tuples.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_build_tuples.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_colamd.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_colamd.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_config.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_create_element.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_create_element.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_dump.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_dump.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_extend_front.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_extend_front.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_free.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_free.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_fsize.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_fsize.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_garbage_collection.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_garbage_collection.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_get_memory.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_get_memory.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_grow_front.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_grow_front.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_init_front.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_init_front.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_internal.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_is_permutation.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_is_permutation.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel_init.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel_init.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel_wrapup.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel_wrapup.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_local_search.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_local_search.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_lsolve.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_lsolve.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_ltsolve.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_ltsolve.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_malloc.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_malloc.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_element.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_element.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_head_block.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_head_block.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_tail_block.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_tail_block.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_free_tail_block.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_free_tail_block.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_init_memoryspace.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_init_memoryspace.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_realloc.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_realloc.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_report_perm.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_report_perm.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_report_vector.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_report_vector.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_row_search.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_row_search.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_scale.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_scale.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_scale_column.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_scale_column.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_set_stats.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_set_stats.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_singletons.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_singletons.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_solve.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_solve.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_start_front.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_start_front.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_store_lu.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_store_lu.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_symbolic_usage.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_symbolic_usage.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_transpose.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_transpose.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_triplet.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_triplet.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_tuple_lengths.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_tuple_lengths.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_usolve.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_usolve.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_utsolve.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_utsolve.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_valid_numeric.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_valid_numeric.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_valid_symbolic.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_valid_symbolic.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umf_version.h [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_col_to_triplet.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_defaults.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_free_numeric.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_free_symbolic.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_get_lunz.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_get_numeric.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_get_symbolic.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_load_numeric.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_load_symbolic.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_numeric.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_qsymbolic.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_control.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_info.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_matrix.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_numeric.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_perm.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_status.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_symbolic.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_triplet.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_vector.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_save_numeric.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_save_symbolic.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_scale.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_solve.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_symbolic.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_tictoc.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_timer.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_transpose.c [new file with mode: 0644]
deal.II/contrib/umfpack/UMFPACK/Source/umfpack_triplet_to_col.c [new file with mode: 0644]

diff --git a/deal.II/contrib/umfpack/AMD/Demo/Makefile b/deal.II/contrib/umfpack/AMD/Demo/Makefile
new file mode 100644 (file)
index 0000000..395cc73
--- /dev/null
@@ -0,0 +1,79 @@
+#------------------------------------------------------------------------------
+# compile the AMD demo (for both GNU make or original make)
+#-----------------------------------------------------------------------------
+
+all: amd_simple amd_demo amd_demo2
+
+include ../Make/Make.include
+
+C = $(CC) $(CFLAGS) $(CONFIG) -I../Include
+
+INC = ../Include/amd.h
+
+../Lib/libamd.a:
+       ( cd ../Source ; make )
+
+../Lib/libamdf77.a:
+       ( cd ../Source ; make fortran )
+
+#------------------------------------------------------------------------------
+# Create the demo program, run it, and compare the output
+#------------------------------------------------------------------------------
+
+dist:
+
+amd_demo: amd_demo.c ../Lib/libamd.a $(INC)
+       $(C) -DDINT -o amd_demo amd_demo.c ../Lib/libamd.a $(LIB)
+       ./amd_demo > my_amd_demo.out
+       - diff amd_demo.out my_amd_demo.out
+
+amd_demo2: amd_demo2.c ../Lib/libamd.a $(INC)
+       $(C) -DDINT -o amd_demo2 amd_demo2.c ../Lib/libamd.a $(LIB)
+       ./amd_demo2 > my_amd_demo2.out
+       - diff amd_demo2.out my_amd_demo2.out
+
+amd_simple: amd_simple.c ../Lib/libamd.a $(INC)
+       $(C) -DDINT -o amd_simple amd_simple.c ../Lib/libamd.a $(LIB)
+       ./amd_simple > my_amd_simple.out
+       - diff amd_simple.out my_amd_simple.out
+
+#------------------------------------------------------------------------------
+# compile the Fortran demo
+#------------------------------------------------------------------------------
+
+fortran: amd_f77demo amd_f77simple
+
+cross: amd_f77cross
+
+amd_f77demo: amd_f77demo.f ../Lib/libamdf77.a
+       $(F77) $(F77FLAGS) -o amd_f77demo amd_f77demo.f ../Lib/libamdf77.a \
+           $(F77LIB)
+       ./amd_f77demo > my_amd_f77demo.out
+       - diff amd_f77demo.out my_amd_f77demo.out
+
+amd_f77simple: amd_f77simple.f ../Lib/libamdf77.a
+       $(F77) $(F77FLAGS) -o amd_f77simple amd_f77simple.f \
+           ../Lib/libamdf77.a $(F77LIB)
+       ./amd_f77simple > my_amd_f77simple.out
+       - diff amd_f77simple.out my_amd_f77simple.out
+
+amd_f77wrapper.o: amd_f77wrapper.c
+       $(C) -DDINT -c amd_f77wrapper.c
+
+amd_f77cross:  amd_f77cross.f amd_f77wrapper.o ../Lib/libamd.a
+       $(F77) $(F77FLAGS) -o amd_f77cross amd_f77cross.f amd_f77wrapper.o \
+           ../Lib/libamd.a $(F77LIB)
+       ./amd_f77cross > my_amd_f77cross.out
+       - diff amd_f77cross.out my_amd_f77cross.out
+
+#------------------------------------------------------------------------------
+# Remove all but the files in the original distribution
+#------------------------------------------------------------------------------
+
+purge: clean
+       - $(RM) amd_demo my_amd_demo.out
+       - $(RM) amd_demo2 my_amd_demo2.out
+       - $(RM) amd_simple my_amd_simple.out
+       - $(RM) amd_f77demo my_amd_f77demo.out
+       - $(RM) amd_f77simple my_amd_f77simple.out
+       - $(RM) amd_f77cross my_amd_f77cross.out
diff --git a/deal.II/contrib/umfpack/AMD/Demo/amd_demo.c b/deal.II/contrib/umfpack/AMD/Demo/amd_demo.c
new file mode 100644 (file)
index 0000000..009dc3d
--- /dev/null
@@ -0,0 +1,169 @@
+/* ========================================================================= */
+/* === AMD demo main program =============================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,  */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README for License.         */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.           */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* A simple C main program that illustrates the use of the ANSI C interface
+ * to AMD.
+ */
+
+#include "amd.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+int main (int argc, char **argv)
+{
+    /* The symmetric can_24 Harwell/Boeing matrix, including upper and lower
+     * triangular parts, and the diagonal entries.  Note that this matrix is
+     * 0-based, with row and column indices in the range 0 to n-1. */
+    int n = 24, nz,
+    Ap [ ] = { 0, 9, 15, 21, 27, 33, 39, 48, 57, 61, 70, 76, 82, 88, 94, 100,
+       106, 110, 119, 128, 137, 143, 152, 156, 160 },
+    Ai [ ] = {
+       /* column  0: */    0, 5, 6, 12, 13, 17, 18, 19, 21,
+       /* column  1: */    1, 8, 9, 13, 14, 17,
+       /* column  2: */    2, 6, 11, 20, 21, 22,
+       /* column  3: */    3, 7, 10, 15, 18, 19,
+       /* column  4: */    4, 7, 9, 14, 15, 16,
+       /* column  5: */    0, 5, 6, 12, 13, 17,
+       /* column  6: */    0, 2, 5, 6, 11, 12, 19, 21, 23,
+       /* column  7: */    3, 4, 7, 9, 14, 15, 16, 17, 18,
+       /* column  8: */    1, 8, 9, 14,
+       /* column  9: */    1, 4, 7, 8, 9, 13, 14, 17, 18,
+       /* column 10: */    3, 10, 18, 19, 20, 21,
+       /* column 11: */    2, 6, 11, 12, 21, 23,
+       /* column 12: */    0, 5, 6, 11, 12, 23,
+       /* column 13: */    0, 1, 5, 9, 13, 17,
+       /* column 14: */    1, 4, 7, 8, 9, 14,
+       /* column 15: */    3, 4, 7, 15, 16, 18,
+       /* column 16: */    4, 7, 15, 16,
+       /* column 17: */    0, 1, 5, 7, 9, 13, 17, 18, 19,
+       /* column 18: */    0, 3, 7, 9, 10, 15, 17, 18, 19,
+       /* column 19: */    0, 3, 6, 10, 17, 18, 19, 20, 21,
+       /* column 20: */    2, 10, 19, 20, 21, 22,
+       /* column 21: */    0, 2, 6, 10, 11, 19, 20, 21, 22,
+       /* column 22: */    2, 20, 21, 22,
+       /* column 23: */    6, 11, 12, 23 } ;
+
+    int P [24], Pinv [24], i, j, k, jnew, p, inew, result ;
+    double Control [AMD_CONTROL], Info [AMD_INFO] ;
+    char A [24][24] ;
+
+    printf ("AMD demo, with the 24-by-24 Harwell/Boeing matrix, can_24:\n") ;
+
+    /* get the default parameters, and print them */
+    amd_defaults (Control) ;
+    amd_control  (Control) ;
+
+    /* print the input matrix */
+    nz = Ap [n] ;
+    printf ("\nInput matrix:  %d-by-%d, with %d entries.\n"
+          "   Note that for a symmetric matrix such as this one, only the\n"
+          "   strictly lower or upper triangular parts would need to be\n"
+          "   passed to AMD, since AMD computes the ordering of A+A'.  The\n"
+          "   diagonal entries are also not needed, since AMD ignores them.\n"
+          , n, n, nz) ;
+    for (j = 0 ; j < n ; j++)
+    {
+       printf ("\nColumn: %d, number of entries: %d, with row indices in"
+               " Ai [%d ... %d]:\n    row indices:",
+               j, Ap [j+1] - Ap [j], Ap [j], Ap [j+1]-1) ;
+       for (p = Ap [j] ; p < Ap [j+1] ; p++)
+       {
+           i = Ai [p] ;
+           printf (" %d", i) ;
+       }
+       printf ("\n") ;
+    }
+
+    /* print a character plot of the input matrix.  This is only reasonable
+     * because the matrix is small. */
+    printf ("\nPlot of input matrix pattern:\n") ;
+    for (j = 0 ; j < n ; j++)
+    {
+       for (i = 0 ; i < n ; i++) A [i][j] = '.' ;
+       for (p = Ap [j] ; p < Ap [j+1] ; p++)
+       {
+           i = Ai [p] ;
+           A [i][j] = 'X' ;
+       }
+    }
+    printf ("    ") ;
+    for (j = 0 ; j < n ; j++) printf (" %1d", j % 10) ;
+    printf ("\n") ;
+    for (i = 0 ; i < n ; i++)
+    {
+       printf ("%2d: ", i) ;
+       for (j = 0 ; j < n ; j++)
+       {
+           printf (" %c", A [i][j]) ;
+       }
+       printf ("\n") ;
+    }
+
+    /* order the matrix */
+    result = amd_order (n, Ap, Ai, P, Control, Info) ;
+    printf ("return value from amd_order: %d (should be %d)\n",
+       result, AMD_OK) ;
+
+    /* print the statistics */
+    amd_info (Info) ;
+
+    if (result != AMD_OK)
+    {
+       printf ("AMD failed\n") ;
+       exit (1) ;
+    }
+
+    /* print the permutation vector, P, and compute the inverse permutation */
+    printf ("Permutation vector:\n") ;
+    for (k = 0 ; k < n ; k++)
+    {
+       /* row/column j is the kth row/column in the permuted matrix */
+       j = P [k] ;
+       Pinv [j] = k ;
+       printf (" %2d", j) ;
+    }
+    printf ("\n\n") ;
+
+    printf ("Inverse permutation vector:\n") ;
+    for (j = 0 ; j < n ; j++)
+    {
+       k = Pinv [j] ;
+       printf (" %2d", k) ;
+    }
+    printf ("\n\n") ;
+
+    /* print a character plot of the permuted matrix. */
+    printf ("\nPlot of permuted matrix pattern:\n") ;
+    for (jnew = 0 ; jnew < n ; jnew++)
+    {
+       j = P [jnew] ;
+       for (inew = 0 ; inew < n ; inew++) A [inew][jnew] = '.' ;
+       for (p = Ap [j] ; p < Ap [j+1] ; p++)
+       {
+           inew = Pinv [Ai [p]] ;
+           A [inew][jnew] = 'X' ;
+       }
+    }
+    printf ("    ") ;
+    for (j = 0 ; j < n ; j++) printf (" %1d", j % 10) ;
+    printf ("\n") ;
+    for (i = 0 ; i < n ; i++)
+    {
+       printf ("%2d: ", i) ;
+       for (j = 0 ; j < n ; j++)
+       {
+           printf (" %c", A [i][j]) ;
+       }
+       printf ("\n") ;
+    }
+
+    return (0) ;
+}
diff --git a/deal.II/contrib/umfpack/AMD/Demo/amd_demo.out b/deal.II/contrib/umfpack/AMD/Demo/amd_demo.out
new file mode 100644 (file)
index 0000000..eb8d845
--- /dev/null
@@ -0,0 +1,177 @@
+AMD demo, with the 24-by-24 Harwell/Boeing matrix, can_24:
+
+amd:  approximate minimum degree ordering, parameters:
+    dense row parameter: 10
+    (rows with more than max (10 * sqrt (n), 16) entries are
+    considered "dense", and placed last in output permutation)
+    aggressive absorption:  yes
+
+
+Input matrix:  24-by-24, with 160 entries.
+   Note that for a symmetric matrix such as this one, only the
+   strictly lower or upper triangular parts would need to be
+   passed to AMD, since AMD computes the ordering of A+A'.  The
+   diagonal entries are also not needed, since AMD ignores them.
+
+Column: 0, number of entries: 9, with row indices in Ai [0 ... 8]:
+    row indices: 0 5 6 12 13 17 18 19 21
+
+Column: 1, number of entries: 6, with row indices in Ai [9 ... 14]:
+    row indices: 1 8 9 13 14 17
+
+Column: 2, number of entries: 6, with row indices in Ai [15 ... 20]:
+    row indices: 2 6 11 20 21 22
+
+Column: 3, number of entries: 6, with row indices in Ai [21 ... 26]:
+    row indices: 3 7 10 15 18 19
+
+Column: 4, number of entries: 6, with row indices in Ai [27 ... 32]:
+    row indices: 4 7 9 14 15 16
+
+Column: 5, number of entries: 6, with row indices in Ai [33 ... 38]:
+    row indices: 0 5 6 12 13 17
+
+Column: 6, number of entries: 9, with row indices in Ai [39 ... 47]:
+    row indices: 0 2 5 6 11 12 19 21 23
+
+Column: 7, number of entries: 9, with row indices in Ai [48 ... 56]:
+    row indices: 3 4 7 9 14 15 16 17 18
+
+Column: 8, number of entries: 4, with row indices in Ai [57 ... 60]:
+    row indices: 1 8 9 14
+
+Column: 9, number of entries: 9, with row indices in Ai [61 ... 69]:
+    row indices: 1 4 7 8 9 13 14 17 18
+
+Column: 10, number of entries: 6, with row indices in Ai [70 ... 75]:
+    row indices: 3 10 18 19 20 21
+
+Column: 11, number of entries: 6, with row indices in Ai [76 ... 81]:
+    row indices: 2 6 11 12 21 23
+
+Column: 12, number of entries: 6, with row indices in Ai [82 ... 87]:
+    row indices: 0 5 6 11 12 23
+
+Column: 13, number of entries: 6, with row indices in Ai [88 ... 93]:
+    row indices: 0 1 5 9 13 17
+
+Column: 14, number of entries: 6, with row indices in Ai [94 ... 99]:
+    row indices: 1 4 7 8 9 14
+
+Column: 15, number of entries: 6, with row indices in Ai [100 ... 105]:
+    row indices: 3 4 7 15 16 18
+
+Column: 16, number of entries: 4, with row indices in Ai [106 ... 109]:
+    row indices: 4 7 15 16
+
+Column: 17, number of entries: 9, with row indices in Ai [110 ... 118]:
+    row indices: 0 1 5 7 9 13 17 18 19
+
+Column: 18, number of entries: 9, with row indices in Ai [119 ... 127]:
+    row indices: 0 3 7 9 10 15 17 18 19
+
+Column: 19, number of entries: 9, with row indices in Ai [128 ... 136]:
+    row indices: 0 3 6 10 17 18 19 20 21
+
+Column: 20, number of entries: 6, with row indices in Ai [137 ... 142]:
+    row indices: 2 10 19 20 21 22
+
+Column: 21, number of entries: 9, with row indices in Ai [143 ... 151]:
+    row indices: 0 2 6 10 11 19 20 21 22
+
+Column: 22, number of entries: 4, with row indices in Ai [152 ... 155]:
+    row indices: 2 20 21 22
+
+Column: 23, number of entries: 4, with row indices in Ai [156 ... 159]:
+    row indices: 6 11 12 23
+
+Plot of input matrix pattern:
+     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+ 0:  X . . . . X X . . . . . X X . . . X X X . X . .
+ 1:  . X . . . . . . X X . . . X X . . X . . . . . .
+ 2:  . . X . . . X . . . . X . . . . . . . . X X X .
+ 3:  . . . X . . . X . . X . . . . X . . X X . . . .
+ 4:  . . . . X . . X . X . . . . X X X . . . . . . .
+ 5:  X . . . . X X . . . . . X X . . . X . . . . . .
+ 6:  X . X . . X X . . . . X X . . . . . . X . X . X
+ 7:  . . . X X . . X . X . . . . X X X X X . . . . .
+ 8:  . X . . . . . . X X . . . . X . . . . . . . . .
+ 9:  . X . . X . . X X X . . . X X . . X X . . . . .
+10:  . . . X . . . . . . X . . . . . . . X X X X . .
+11:  . . X . . . X . . . . X X . . . . . . . . X . X
+12:  X . . . . X X . . . . X X . . . . . . . . . . X
+13:  X X . . . X . . . X . . . X . . . X . . . . . .
+14:  . X . . X . . X X X . . . . X . . . . . . . . .
+15:  . . . X X . . X . . . . . . . X X . X . . . . .
+16:  . . . . X . . X . . . . . . . X X . . . . . . .
+17:  X X . . . X . X . X . . . X . . . X X X . . . .
+18:  X . . X . . . X . X X . . . . X . X X X . . . .
+19:  X . . X . . X . . . X . . . . . . X X X X X . .
+20:  . . X . . . . . . . X . . . . . . . . X X X X .
+21:  X . X . . . X . . . X X . . . . . . . X X X X .
+22:  . . X . . . . . . . . . . . . . . . . . X X X .
+23:  . . . . . . X . . . . X X . . . . . . . . . . X
+return value from amd_order: 0 (should be 0)
+
+amd:  approximate minimum degree ordering, results:
+    status: OK
+    n, dimension of A:                                  24
+    nz, number of nonzeros in A:                        160
+    symmetry of A:                                      1.0000
+    number of nonzeros on diagonal:                     24
+    nonzeros in pattern of A+A' (excl. diagonal):       136
+    # dense rows/columns of A+A':                       0
+    memory used, in bytes:                              1516
+    # of memory compactions:                            0
+
+    The following approximate statistics are for a subsequent
+    factorization of A(P,P) + A(P,P)'.  They are slight upper
+    bounds if there are no dense rows/columns in A+A', and become
+    looser if dense rows/columns exist.
+
+    nonzeros in L (excluding diagonal):                 97
+    nonzeros in L (including diagonal):                 121
+    # divide operations for LDL' or LU:                 97
+    # multiply-subtract operations for LDL':            275
+    # multiply-subtract operations for LU:              453
+    max nz. in any column of L (incl. diagonal):        8
+
+    chol flop count for real A, sqrt counted as 1 flop: 671
+    LDL' flop count for real A:                         647
+    LDL' flop count for complex A:                      3073
+    LU flop count for real A (with no pivoting):        1003
+    LU flop count for complex A (with no pivoting):     4497
+
+Permutation vector:
+ 22 20 10 23 12  5 16  8 14  4 15  7  1  9 13 17  0  2  3  6 11 18 21 19
+
+Inverse permutation vector:
+ 16 12 17 18  9  5 19 11  7 13  2 20  4 14  8 10  6 15 21 23  1 22  0  3
+
+
+Plot of permuted matrix pattern:
+     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+ 0:  X X . . . . . . . . . . . . . . . X . . . . X .
+ 1:  X X X . . . . . . . . . . . . . . X . . . . X X
+ 2:  . X X . . . . . . . . . . . . . . . X . . X X X
+ 3:  . . . X X . . . . . . . . . . . . . . X X . . .
+ 4:  . . . X X X . . . . . . . . . . X . . X X . . .
+ 5:  . . . . X X . . . . . . . . X X X . . X . . . .
+ 6:  . . . . . . X . . X X X . . . . . . . . . . . .
+ 7:  . . . . . . . X X . . . X X . . . . . . . . . .
+ 8:  . . . . . . . X X X . X X X . . . . . . . . . .
+ 9:  . . . . . . X . X X X X . X . . . . . . . . . .
+10:  . . . . . . X . . X X X . . . . . . X . . X . .
+11:  . . . . . . X . X X X X . X . X . . X . . X . .
+12:  . . . . . . . X X . . . X X X X . . . . . . . .
+13:  . . . . . . . X X X . X X X X X . . . . . X . .
+14:  . . . . . X . . . . . . X X X X X . . . . . . .
+15:  . . . . . X . . . . . X X X X X X . . . . X . X
+16:  . . . . X X . . . . . . . . X X X . . X . X X X
+17:  X X . . . . . . . . . . . . . . . X . X X . X .
+18:  . . X . . . . . . . X X . . . . . . X . . X . X
+19:  . . . X X X . . . . . . . . . . X X . X X . X X
+20:  . . . X X . . . . . . . . . . . . X . X X . X .
+21:  . . X . . . . . . . X X . X . X X . X . . X . X
+22:  X X X . . . . . . . . . . . . . X X . X X . X X
+23:  . X X . . . . . . . . . . . . X X . X X . X X X
diff --git a/deal.II/contrib/umfpack/AMD/Demo/amd_demo2.c b/deal.II/contrib/umfpack/AMD/Demo/amd_demo2.c
new file mode 100644 (file)
index 0000000..450d7c5
--- /dev/null
@@ -0,0 +1,261 @@
+/* ========================================================================= */
+/* === AMD demo main program (jumbled matrix version) ====================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,  */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README for License.         */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.           */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* A simple C main program that illustrates the use of the ANSI C interface
+ * to AMD.
+ *
+ * Identical to amd_demo.c, except that it operates on an input matrix that has
+ * unsorted columns and duplicate entries.
+ */
+
+#include "amd.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+int main (int argc, char **argv)
+{
+    /* The symmetric can_24 Harwell/Boeing matrix (jumbled, and not symmetric).
+     * Since AMD operates on A+A', only A(i,j) or A(j,i) need to be specified,
+     * or both.  The diagonal entries are optional (some are missing).
+     * There are many duplicate entries, which must be removed. */
+    int n = 24, nz,
+    Ap [ ] = { 0, 9, 14, 20, 28, 33, 37, 44, 53, 58, 63, 63, 66, 69, 72, 75,
+             78, 82, 86, 91, 97, 101, 112, 112, 116 },
+    Ai [ ] = {
+       /* column  0: */    0, 17, 18, 21, 5, 12, 5, 0, 13,
+       /* column  1: */    14, 1, 8, 13, 17,
+       /* column  2: */    2, 20, 11, 6, 11, 22,
+       /* column  3: */    3, 3, 10, 7, 18, 18, 15, 19,
+       /* column  4: */    7, 9, 15, 14, 16,
+       /* column  5: */    5, 13, 6, 17,
+       /* column  6: */    5, 0, 11, 6, 12, 6, 23,
+       /* column  7: */    3, 4, 9, 7, 14, 16, 15, 17, 18,
+       /* column  8: */    1, 9, 14, 14, 14,
+       /* column  9: */    7, 13, 8, 1, 17,
+       /* column 10: */
+       /* column 11: */    2, 12, 23,
+       /* column 12: */    5, 11, 12,
+       /* column 13: */    0, 13, 17,
+       /* column 14: */    1, 9, 14,
+       /* column 15: */    3, 15, 16,
+       /* column 16: */    16, 4, 4, 15,
+       /* column 17: */    13, 17, 19, 17,
+       /* column 18: */    15, 17, 19, 9, 10,
+       /* column 19: */    17, 19, 20, 0, 6, 10,
+       /* column 20: */    22, 10, 20, 21,
+       /* column 21: */    6, 2, 10, 19, 20, 11, 21, 22, 22, 22, 22,
+       /* column 22: */
+       /* column 23: */    12, 11, 12, 23 } ;
+
+    int Rp [25], Ri [116] ;
+    int P [24], Pinv [24], i, j, k, jnew, p, inew, result ;
+    double Control [AMD_CONTROL], Info [AMD_INFO] ;
+    char A [24][24] ;
+
+    printf ("AMD demo, with a jumbled version of the 24-by-24\n") ;
+    printf ("Harwell/Boeing matrix, can_24:\n") ;
+
+    /* get the default parameters, and print them */
+    amd_defaults (Control) ;
+    amd_control  (Control) ;
+
+    /* print the input matrix */
+    nz = Ap [n] ;
+    printf ("\nJumbled input matrix:  %d-by-%d, with %d entries.\n"
+          "   Note that for a symmetric matrix such as this one, only the\n"
+          "   strictly lower or upper triangular parts would need to be\n"
+          "   passed to AMD, since AMD computes the ordering of A+A'.  The\n"
+          "   diagonal entries are also not needed, since AMD ignores them.\n"
+          "   This version of the matrix has jumbled columns and duplicate\n"
+          "   row indices, and must be fixed by amd_preprocess prior to\n"
+          "   ordering it with amd_order.\n" , n, n, nz) ;
+    for (j = 0 ; j < n ; j++)
+    {
+       printf ("\nColumn: %d, number of entries: %d, with row indices in"
+               " Ai [%d ... %d]:\n    row indices:",
+               j, Ap [j+1] - Ap [j], Ap [j], Ap [j+1]-1) ;
+       for (p = Ap [j] ; p < Ap [j+1] ; p++)
+       {
+           i = Ai [p] ;
+           printf (" %d", i) ;
+       }
+       printf ("\n") ;
+    }
+
+    /* print a character plot of the input matrix.  This is only reasonable
+     * because the matrix is small. */
+    printf ("\nPlot of (jumbled) input matrix pattern:\n") ;
+    for (j = 0 ; j < n ; j++)
+    {
+       for (i = 0 ; i < n ; i++) A [i][j] = '.' ;
+       for (p = Ap [j] ; p < Ap [j+1] ; p++)
+       {
+           i = Ai [p] ;
+           A [i][j] = 'X' ;
+       }
+    }
+    printf ("    ") ;
+    for (j = 0 ; j < n ; j++) printf (" %1d", j % 10) ;
+    printf ("\n") ;
+    for (i = 0 ; i < n ; i++)
+    {
+       printf ("%2d: ", i) ;
+       for (j = 0 ; j < n ; j++)
+       {
+           printf (" %c", A [i][j]) ;
+       }
+       printf ("\n") ;
+    }
+
+    /* sort, remove duplicates, and transpose A to get R */
+    result = amd_preprocess (n, Ap, Ai, Rp, Ri) ;
+    printf ("return value from amd_preprocess: %d (should be %d)\n",
+       result, AMD_OK) ;
+
+    if (result != AMD_OK)
+    {
+       printf ("AMD failed\n") ;
+       exit (1) ;
+    }
+
+    /* print the sorted/transposed matrix R */
+    printf ("\nThe column-oriented form of the sorted/transposed matrix R:\n");
+    for (j = 0 ; j < n ; j++)
+    {
+       printf ("\nColumn: %d, number of entries: %d, with row indices in"
+               " Ri [%d ... %d]:\n    row indices:",
+               j, Rp [j+1] - Rp [j], Rp [j], Rp [j+1]-1) ;
+       for (p = Rp [j] ; p < Rp [j+1] ; p++)
+       {
+           i = Ri [p] ;
+           printf (" %d", i) ;
+       }
+       printf ("\n") ;
+    }
+
+    /* print a character plot of the matrix R. */
+    printf ("\nPlot of the sorted/transposed matrix R:\n") ;
+    for (j = 0 ; j < n ; j++)
+    {
+       for (i = 0 ; i < n ; i++) A [i][j] = '.' ;
+       for (p = Rp [j] ; p < Rp [j+1] ; p++)
+       {
+           i = Ri [p] ;
+           A [i][j] = 'X' ;
+       }
+    }
+    printf ("    ") ;
+    for (j = 0 ; j < n ; j++) printf (" %1d", j % 10) ;
+    printf (" \n") ;
+    for (i = 0 ; i < n ; i++)
+    {
+       printf ("%2d: ", i) ;
+       for (j = 0 ; j < n ; j++)
+       {
+           printf (" %c", A [i][j]) ;
+       }
+       printf (" \n") ;
+    }
+
+    /* print a character plot of the matrix R+R'. */
+    printf ("\nPlot of symmetric matrix to be ordered by amd_order:\n") ;
+    for (j = 0 ; j < n ; j++)
+    {
+       for (i = 0 ; i < n ; i++) A [i][j] = '.' ;
+    }
+    for (j = 0 ; j < n ; j++)
+    {
+       A [j][j] = 'X' ;
+       for (p = Rp [j] ; p < Rp [j+1] ; p++)
+       {
+           i = Ri [p] ;
+           A [i][j] = 'X' ;
+           A [j][i] = 'X' ;
+       }
+    }
+    printf ("    ") ;
+    for (j = 0 ; j < n ; j++) printf (" %1d", j % 10) ;
+    printf ("\n") ;
+    for (i = 0 ; i < n ; i++)
+    {
+       printf ("%2d: ", i) ;
+       for (j = 0 ; j < n ; j++)
+       {
+           printf (" %c", A [i][j]) ;
+       }
+       printf ("\n") ;
+    }
+
+    /* order the matrix */
+    result = amd_order (n, Rp, Ri, P, Control, Info) ;
+    printf ("return value from amd_order: %d (should be %d)\n",
+       result, AMD_OK) ;
+
+    /* print the statistics */
+    amd_info (Info) ;
+
+    if (result != AMD_OK)
+    {
+       printf ("AMD failed\n") ;
+       exit (1) ;
+    }
+
+    /* print the permutation vector, P, and compute the inverse permutation */
+    printf ("Permutation vector:\n") ;
+    for (k = 0 ; k < n ; k++)
+    {
+       /* row/column j is the kth row/column in the permuted matrix */
+       j = P [k] ;
+       Pinv [j] = k ;
+       printf (" %2d", j) ;
+    }
+    printf ("\n\n") ;
+
+    printf ("Inverse permutation vector:\n") ;
+    for (j = 0 ; j < n ; j++)
+    {
+       k = Pinv [j] ;
+       printf (" %2d", k) ;
+    }
+    printf ("\n\n") ;
+
+    /* print a character plot of the permuted matrix. */
+    printf ("\nPlot of (symmetrized) permuted matrix pattern:\n") ;
+    for (j = 0 ; j < n ; j++)
+    {
+       for (i = 0 ; i < n ; i++) A [i][j] = '.' ;
+    }
+    for (jnew = 0 ; jnew < n ; jnew++)
+    {
+       j = P [jnew] ;
+       A [jnew][jnew] = 'X' ;
+       for (p = Rp [j] ; p < Rp [j+1] ; p++)
+       {
+           inew = Pinv [Ri [p]] ;
+           A [inew][jnew] = 'X' ;
+           A [jnew][inew] = 'X' ;
+       }
+    }
+    printf ("    ") ;
+    for (j = 0 ; j < n ; j++) printf (" %1d", j % 10) ;
+    printf ("\n") ;
+    for (i = 0 ; i < n ; i++)
+    {
+       printf ("%2d: ", i) ;
+       for (j = 0 ; j < n ; j++)
+       {
+           printf (" %c", A [i][j]) ;
+       }
+       printf ("\n") ;
+    }
+
+    return (0) ;
+}
diff --git a/deal.II/contrib/umfpack/AMD/Demo/amd_demo2.out b/deal.II/contrib/umfpack/AMD/Demo/amd_demo2.out
new file mode 100644 (file)
index 0000000..c03e8d5
--- /dev/null
@@ -0,0 +1,310 @@
+AMD demo, with a jumbled version of the 24-by-24
+Harwell/Boeing matrix, can_24:
+
+amd:  approximate minimum degree ordering, parameters:
+    dense row parameter: 10
+    (rows with more than max (10 * sqrt (n), 16) entries are
+    considered "dense", and placed last in output permutation)
+    aggressive absorption:  yes
+
+
+Jumbled input matrix:  24-by-24, with 116 entries.
+   Note that for a symmetric matrix such as this one, only the
+   strictly lower or upper triangular parts would need to be
+   passed to AMD, since AMD computes the ordering of A+A'.  The
+   diagonal entries are also not needed, since AMD ignores them.
+   This version of the matrix has jumbled columns and duplicate
+   row indices, and must be fixed by amd_preprocess prior to
+   ordering it with amd_order.
+
+Column: 0, number of entries: 9, with row indices in Ai [0 ... 8]:
+    row indices: 0 17 18 21 5 12 5 0 13
+
+Column: 1, number of entries: 5, with row indices in Ai [9 ... 13]:
+    row indices: 14 1 8 13 17
+
+Column: 2, number of entries: 6, with row indices in Ai [14 ... 19]:
+    row indices: 2 20 11 6 11 22
+
+Column: 3, number of entries: 8, with row indices in Ai [20 ... 27]:
+    row indices: 3 3 10 7 18 18 15 19
+
+Column: 4, number of entries: 5, with row indices in Ai [28 ... 32]:
+    row indices: 7 9 15 14 16
+
+Column: 5, number of entries: 4, with row indices in Ai [33 ... 36]:
+    row indices: 5 13 6 17
+
+Column: 6, number of entries: 7, with row indices in Ai [37 ... 43]:
+    row indices: 5 0 11 6 12 6 23
+
+Column: 7, number of entries: 9, with row indices in Ai [44 ... 52]:
+    row indices: 3 4 9 7 14 16 15 17 18
+
+Column: 8, number of entries: 5, with row indices in Ai [53 ... 57]:
+    row indices: 1 9 14 14 14
+
+Column: 9, number of entries: 5, with row indices in Ai [58 ... 62]:
+    row indices: 7 13 8 1 17
+
+Column: 10, number of entries: 0, with row indices in Ai [63 ... 62]:
+    row indices:
+
+Column: 11, number of entries: 3, with row indices in Ai [63 ... 65]:
+    row indices: 2 12 23
+
+Column: 12, number of entries: 3, with row indices in Ai [66 ... 68]:
+    row indices: 5 11 12
+
+Column: 13, number of entries: 3, with row indices in Ai [69 ... 71]:
+    row indices: 0 13 17
+
+Column: 14, number of entries: 3, with row indices in Ai [72 ... 74]:
+    row indices: 1 9 14
+
+Column: 15, number of entries: 3, with row indices in Ai [75 ... 77]:
+    row indices: 3 15 16
+
+Column: 16, number of entries: 4, with row indices in Ai [78 ... 81]:
+    row indices: 16 4 4 15
+
+Column: 17, number of entries: 4, with row indices in Ai [82 ... 85]:
+    row indices: 13 17 19 17
+
+Column: 18, number of entries: 5, with row indices in Ai [86 ... 90]:
+    row indices: 15 17 19 9 10
+
+Column: 19, number of entries: 6, with row indices in Ai [91 ... 96]:
+    row indices: 17 19 20 0 6 10
+
+Column: 20, number of entries: 4, with row indices in Ai [97 ... 100]:
+    row indices: 22 10 20 21
+
+Column: 21, number of entries: 11, with row indices in Ai [101 ... 111]:
+    row indices: 6 2 10 19 20 11 21 22 22 22 22
+
+Column: 22, number of entries: 0, with row indices in Ai [112 ... 111]:
+    row indices:
+
+Column: 23, number of entries: 4, with row indices in Ai [112 ... 115]:
+    row indices: 12 11 12 23
+
+Plot of (jumbled) input matrix pattern:
+     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+ 0:  X . . . . . X . . . . . . X . . . . . X . . . .
+ 1:  . X . . . . . . X X . . . . X . . . . . . . . .
+ 2:  . . X . . . . . . . . X . . . . . . . . . X . .
+ 3:  . . . X . . . X . . . . . . . X . . . . . . . .
+ 4:  . . . . . . . X . . . . . . . . X . . . . . . .
+ 5:  X . . . . X X . . . . . X . . . . . . . . . . .
+ 6:  . . X . . X X . . . . . . . . . . . . X . X . .
+ 7:  . . . X X . . X . X . . . . . . . . . . . . . .
+ 8:  . X . . . . . . . X . . . . . . . . . . . . . .
+ 9:  . . . . X . . X X . . . . . X . . . X . . . . .
+10:  . . . X . . . . . . . . . . . . . . X X X X . .
+11:  . . X . . . X . . . . . X . . . . . . . . X . X
+12:  X . . . . . X . . . . X X . . . . . . . . . . X
+13:  X X . . . X . . . X . . . X . . . X . . . . . .
+14:  . X . . X . . X X . . . . . X . . . . . . . . .
+15:  . . . X X . . X . . . . . . . X X . X . . . . .
+16:  . . . . X . . X . . . . . . . X X . . . . . . .
+17:  X X . . . X . X . X . . . X . . . X X X . . . .
+18:  X . . X . . . X . . . . . . . . . . . . . . . .
+19:  . . . X . . . . . . . . . . . . . X X X . X . .
+20:  . . X . . . . . . . . . . . . . . . . X X X . .
+21:  X . . . . . . . . . . . . . . . . . . . X X . .
+22:  . . X . . . . . . . . . . . . . . . . . X X . .
+23:  . . . . . . X . . . . X . . . . . . . . . . . X
+return value from amd_preprocess: 0 (should be 0)
+
+The column-oriented form of the sorted/transposed matrix R:
+
+Column: 0, number of entries: 4, with row indices in Ri [0 ... 3]:
+    row indices: 0 6 13 19
+
+Column: 1, number of entries: 4, with row indices in Ri [4 ... 7]:
+    row indices: 1 8 9 14
+
+Column: 2, number of entries: 3, with row indices in Ri [8 ... 10]:
+    row indices: 2 11 21
+
+Column: 3, number of entries: 3, with row indices in Ri [11 ... 13]:
+    row indices: 3 7 15
+
+Column: 4, number of entries: 2, with row indices in Ri [14 ... 15]:
+    row indices: 7 16
+
+Column: 5, number of entries: 4, with row indices in Ri [16 ... 19]:
+    row indices: 0 5 6 12
+
+Column: 6, number of entries: 5, with row indices in Ri [20 ... 24]:
+    row indices: 2 5 6 19 21
+
+Column: 7, number of entries: 4, with row indices in Ri [25 ... 28]:
+    row indices: 3 4 7 9
+
+Column: 8, number of entries: 2, with row indices in Ri [29 ... 30]:
+    row indices: 1 9
+
+Column: 9, number of entries: 5, with row indices in Ri [31 ... 35]:
+    row indices: 4 7 8 14 18
+
+Column: 10, number of entries: 5, with row indices in Ri [36 ... 40]:
+    row indices: 3 18 19 20 21
+
+Column: 11, number of entries: 5, with row indices in Ri [41 ... 45]:
+    row indices: 2 6 12 21 23
+
+Column: 12, number of entries: 5, with row indices in Ri [46 ... 50]:
+    row indices: 0 6 11 12 23
+
+Column: 13, number of entries: 6, with row indices in Ri [51 ... 56]:
+    row indices: 0 1 5 9 13 17
+
+Column: 14, number of entries: 5, with row indices in Ri [57 ... 61]:
+    row indices: 1 4 7 8 14
+
+Column: 15, number of entries: 6, with row indices in Ri [62 ... 67]:
+    row indices: 3 4 7 15 16 18
+
+Column: 16, number of entries: 4, with row indices in Ri [68 ... 71]:
+    row indices: 4 7 15 16
+
+Column: 17, number of entries: 9, with row indices in Ri [72 ... 80]:
+    row indices: 0 1 5 7 9 13 17 18 19
+
+Column: 18, number of entries: 3, with row indices in Ri [81 ... 83]:
+    row indices: 0 3 7
+
+Column: 19, number of entries: 5, with row indices in Ri [84 ... 88]:
+    row indices: 3 17 18 19 21
+
+Column: 20, number of entries: 4, with row indices in Ri [89 ... 92]:
+    row indices: 2 19 20 21
+
+Column: 21, number of entries: 3, with row indices in Ri [93 ... 95]:
+    row indices: 0 20 21
+
+Column: 22, number of entries: 3, with row indices in Ri [96 ... 98]:
+    row indices: 2 20 21
+
+Column: 23, number of entries: 3, with row indices in Ri [99 ... 101]:
+    row indices: 6 11 23
+
+Plot of the sorted/transposed matrix R:
+     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 
+ 0:  X . . . . X . . . . . . X X . . . X X . . X . . 
+ 1:  . X . . . . . . X . . . . X X . . X . . . . . . 
+ 2:  . . X . . . X . . . . X . . . . . . . . X . X . 
+ 3:  . . . X . . . X . . X . . . . X . . X X . . . . 
+ 4:  . . . . . . . X . X . . . . X X X . . . . . . . 
+ 5:  . . . . . X X . . . . . . X . . . X . . . . . . 
+ 6:  X . . . . X X . . . . X X . . . . . . . . . . X 
+ 7:  . . . X X . . X . X . . . . X X X X X . . . . . 
+ 8:  . X . . . . . . . X . . . . X . . . . . . . . . 
+ 9:  . X . . . . . X X . . . . X . . . X . . . . . . 
+10:  . . . . . . . . . . . . . . . . . . . . . . . . 
+11:  . . X . . . . . . . . . X . . . . . . . . . . X 
+12:  . . . . . X . . . . . X X . . . . . . . . . . . 
+13:  X . . . . . . . . . . . . X . . . X . . . . . . 
+14:  . X . . . . . . . X . . . . X . . . . . . . . . 
+15:  . . . X . . . . . . . . . . . X X . . . . . . . 
+16:  . . . . X . . . . . . . . . . X X . . . . . . . 
+17:  . . . . . . . . . . . . . X . . . X . X . . . . 
+18:  . . . . . . . . . X X . . . . X . X . X . . . . 
+19:  X . . . . . X . . . X . . . . . . X . X X . . . 
+20:  . . . . . . . . . . X . . . . . . . . . X X X . 
+21:  . . X . . . X . . . X X . . . . . . . X X X X . 
+22:  . . . . . . . . . . . . . . . . . . . . . . . . 
+23:  . . . . . . . . . . . X X . . . . . . . . . . X 
+
+Plot of symmetric matrix to be ordered by amd_order:
+     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+ 0:  X . . . . X X . . . . . X X . . . X X X . X . .
+ 1:  . X . . . . . . X X . . . X X . . X . . . . . .
+ 2:  . . X . . . X . . . . X . . . . . . . . X X X .
+ 3:  . . . X . . . X . . X . . . . X . . X X . . . .
+ 4:  . . . . X . . X . X . . . . X X X . . . . . . .
+ 5:  X . . . . X X . . . . . X X . . . X . . . . . .
+ 6:  X . X . . X X . . . . X X . . . . . . X . X . X
+ 7:  . . . X X . . X . X . . . . X X X X X . . . . .
+ 8:  . X . . . . . . X X . . . . X . . . . . . . . .
+ 9:  . X . . X . . X X X . . . X X . . X X . . . . .
+10:  . . . X . . . . . . X . . . . . . . X X X X . .
+11:  . . X . . . X . . . . X X . . . . . . . . X . X
+12:  X . . . . X X . . . . X X . . . . . . . . . . X
+13:  X X . . . X . . . X . . . X . . . X . . . . . .
+14:  . X . . X . . X X X . . . . X . . . . . . . . .
+15:  . . . X X . . X . . . . . . . X X . X . . . . .
+16:  . . . . X . . X . . . . . . . X X . . . . . . .
+17:  X X . . . X . X . X . . . X . . . X X X . . . .
+18:  X . . X . . . X . X X . . . . X . X X X . . . .
+19:  X . . X . . X . . . X . . . . . . X X X X X . .
+20:  . . X . . . . . . . X . . . . . . . . X X X X .
+21:  X . X . . . X . . . X X . . . . . . . X X X X .
+22:  . . X . . . . . . . . . . . . . . . . . X X X .
+23:  . . . . . . X . . . . X X . . . . . . . . . . X
+return value from amd_order: 0 (should be 0)
+
+amd:  approximate minimum degree ordering, results:
+    status: OK
+    n, dimension of A:                                  24
+    nz, number of nonzeros in A:                        102
+    symmetry of A:                                      0.4000
+    number of nonzeros on diagonal:                     17
+    nonzeros in pattern of A+A' (excl. diagonal):       136
+    # dense rows/columns of A+A':                       0
+    memory used, in bytes:                              1516
+    # of memory compactions:                            0
+
+    The following approximate statistics are for a subsequent
+    factorization of A(P,P) + A(P,P)'.  They are slight upper
+    bounds if there are no dense rows/columns in A+A', and become
+    looser if dense rows/columns exist.
+
+    nonzeros in L (excluding diagonal):                 97
+    nonzeros in L (including diagonal):                 121
+    # divide operations for LDL' or LU:                 97
+    # multiply-subtract operations for LDL':            275
+    # multiply-subtract operations for LU:              453
+    max nz. in any column of L (incl. diagonal):        8
+
+    chol flop count for real A, sqrt counted as 1 flop: 671
+    LDL' flop count for real A:                         647
+    LDL' flop count for complex A:                      3073
+    LU flop count for real A (with no pivoting):        1003
+    LU flop count for complex A (with no pivoting):     4497
+
+Permutation vector:
+ 22 20 10 23 12  5 16  8 14  4 15  7  1  9 13 17  0  2  3  6 11 18 21 19
+
+Inverse permutation vector:
+ 16 12 17 18  9  5 19 11  7 13  2 20  4 14  8 10  6 15 21 23  1 22  0  3
+
+
+Plot of (symmetrized) permuted matrix pattern:
+     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+ 0:  X X . . . . . . . . . . . . . . . X . . . . X .
+ 1:  X X X . . . . . . . . . . . . . . X . . . . X X
+ 2:  . X X . . . . . . . . . . . . . . . X . . X X X
+ 3:  . . . X X . . . . . . . . . . . . . . X X . . .
+ 4:  . . . X X X . . . . . . . . . . X . . X X . . .
+ 5:  . . . . X X . . . . . . . . X X X . . X . . . .
+ 6:  . . . . . . X . . X X X . . . . . . . . . . . .
+ 7:  . . . . . . . X X . . . X X . . . . . . . . . .
+ 8:  . . . . . . . X X X . X X X . . . . . . . . . .
+ 9:  . . . . . . X . X X X X . X . . . . . . . . . .
+10:  . . . . . . X . . X X X . . . . . . X . . X . .
+11:  . . . . . . X . X X X X . X . X . . X . . X . .
+12:  . . . . . . . X X . . . X X X X . . . . . . . .
+13:  . . . . . . . X X X . X X X X X . . . . . X . .
+14:  . . . . . X . . . . . . X X X X X . . . . . . .
+15:  . . . . . X . . . . . X X X X X X . . . . X . X
+16:  . . . . X X . . . . . . . . X X X . . X . X X X
+17:  X X . . . . . . . . . . . . . . . X . X X . X .
+18:  . . X . . . . . . . X X . . . . . . X . . X . X
+19:  . . . X X X . . . . . . . . . . X X . X X . X X
+20:  . . . X X . . . . . . . . . . . . X . X X . X .
+21:  . . X . . . . . . . X X . X . X X . X . . X . X
+22:  X X X . . . . . . . . . . . . . X X . X X . X X
+23:  . X X . . . . . . . . . . . . X X . X X . X X X
diff --git a/deal.II/contrib/umfpack/AMD/Demo/amd_f77cross.f b/deal.II/contrib/umfpack/AMD/Demo/amd_f77cross.f
new file mode 100644 (file)
index 0000000..ddbfd00
--- /dev/null
@@ -0,0 +1,51 @@
+C ======================================================================
+C === AMD_cross ========================================================
+C ======================================================================
+
+C ----------------------------------------------------------------------
+C AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A.
+C Davis, Patrick R. Amestoy, and Iain S. Duff.  See ../README for
+C License.  email: davis@cise.ufl.edu    CISE Department, Univ. of
+C Florida.  web: http://www.cise.ufl.edu/research/sparse/amd
+C ----------------------------------------------------------------------
+
+C This program provides an example of how to call the C version of AMD
+C from a Fortran program.  It is HIGHLY non-portable.
+
+C The amd_order routine returns PERM (1) < 0 if an error occurs.
+C (-1: out of memory, -2: invalid matrix)
+
+C Note that the input matrix is 0-based.  From Fortran, column j of the
+C matrix is in AI (AP (I)+1 ... AP (I+1)).  The row indices in this
+C set are in the range 0 to N-1.  To demonstrate this translation,
+C the input matrix is printed in 1-based form.  This program uses
+C the same 5-by-5 test matrix as amd_simple.c.
+
+        INTEGER N, NZ, K, P
+        PARAMETER (N = 5, NZ = 14)
+        INTEGER AP (N+1), AI (NZ), PERM (N)
+        DATA AP / 0,   2,       6,       10,  12, 14 /
+        DATA AI / 0,1, 0,1,2,4, 1,2,3,4, 2,3, 1,4    /
+        DOUBLE PRECISION CONTROL (5), INFO (20)
+
+C       print the input matrix
+        PRINT 10, N, N, NZ
+10      FORMAT ('Input matrix:', I2, '-by-', I2, ' with',I3,' entries')
+        DO 40 J = 1, N
+            PRINT 20, J, AP (J+1) - AP (J), AP (J)+1, AP (J+1)
+20          FORMAT ( /, 'Column: ', I2, ' number of entries: ', I2,
+     $          ' with row indices in AI (', I3, ' ... ', I3, ')')
+            PRINT 30, ((AI (P) + 1), P = AP (J) + 1, AP (J+1))
+30          FORMAT ('    row indices: ', 24I3)
+40      CONTINUE
+
+        CALL AMDDEFAULTS (CONTROL)
+        CALL AMDORDER (N, AP, AI, PERM, CONTROL, INFO)
+        CALL AMDINFO (INFO)
+
+        DO 60 K = 1, N
+            PRINT 50, K, PERM (K) + 1
+50          FORMAT ('PERM (',I2,') = ', I2)
+60      CONTINUE
+        END
+
diff --git a/deal.II/contrib/umfpack/AMD/Demo/amd_f77cross.out b/deal.II/contrib/umfpack/AMD/Demo/amd_f77cross.out
new file mode 100644 (file)
index 0000000..6d8a670
--- /dev/null
@@ -0,0 +1,51 @@
+Input matrix: 5-by- 5 with 14 entries
+
+Column:  1 number of entries:  2 with row indices in AI (  1 ...   2)
+    row indices:   1  2
+
+Column:  2 number of entries:  4 with row indices in AI (  3 ...   6)
+    row indices:   1  2  3  5
+
+Column:  3 number of entries:  4 with row indices in AI (  7 ...  10)
+    row indices:   2  3  4  5
+
+Column:  4 number of entries:  2 with row indices in AI ( 11 ...  12)
+    row indices:   3  4
+
+Column:  5 number of entries:  2 with row indices in AI ( 13 ...  14)
+    row indices:   2  5
+
+amd:  approximate minimum degree ordering, results:
+    status: OK
+    n, dimension of A:                                  5
+    nz, number of nonzeros in A:                        14
+    symmetry of A:                                      0.8889
+    number of nonzeros on diagonal:                     5
+    nonzeros in pattern of A+A' (excl. diagonal):       10
+    # dense rows/columns of A+A':                       0
+    memory used, in bytes:                              228
+    # of memory compactions:                            0
+
+    The following approximate statistics are for a subsequent
+    factorization of A(P,P) + A(P,P)'.  They are slight upper
+    bounds if there are no dense rows/columns in A+A', and become
+    looser if dense rows/columns exist.
+
+    nonzeros in L (excluding diagonal):                 5
+    nonzeros in L (including diagonal):                 10
+    # divide operations for LDL' or LU:                 5
+    # multiply-subtract operations for LDL':            6
+    # multiply-subtract operations for LU:              7
+    max nz. in any column of L (incl. diagonal):        3
+
+    chol flop count for real A, sqrt counted as 1 flop: 22
+    LDL' flop count for real A:                         17
+    LDL' flop count for complex A:                      93
+    LU flop count for real A (with no pivoting):        19
+    LU flop count for complex A (with no pivoting):     101
+
+PERM ( 1) =  1
+PERM ( 2) =  4
+PERM ( 3) =  3
+PERM ( 4) =  5
+PERM ( 5) =  2
diff --git a/deal.II/contrib/umfpack/AMD/Demo/amd_f77demo.f b/deal.II/contrib/umfpack/AMD/Demo/amd_f77demo.f
new file mode 100644 (file)
index 0000000..3ed47ab
--- /dev/null
@@ -0,0 +1,161 @@
+C ======================================================================
+C === Fortran AMD demo main program ====================================
+C ======================================================================
+
+C ----------------------------------------------------------------------
+C AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A.
+C Davis, Patrick R. Amestoy, and Iain S. Duff.  See ../README for
+C License.  email: davis@cise.ufl.edu    CISE Department, Univ. of
+C Florida.  web: http://www.cise.ufl.edu/research/sparse/amd
+C ----------------------------------------------------------------------
+
+C A simple Fortran 77 main program that illustrates the use of the
+C Fortran version of AMD (both the AMD and AMDBAR routines).  Note
+C that aggressive absorption has no effect on this particular matrix.
+
+C       AP and AI contain the symmetric can_24 Harwell/Boeing matrix,
+C       including upper and lower triangular parts, but excluding the
+C       diagonal entries.  Note that this matrix is 1-based, with row
+C       and column indices in the range 1 to N.
+
+        INTEGER N, NZ, IWLEN, PFREE, I, J, K, JNEW, P, INEW,
+     $      METHOD, NCMPA
+        PARAMETER (N = 24, NZ = 136, IWLEN = 200)
+        INTEGER PE (N), DEGREE (N), NV (N), NEXT (N), PERM (N), W (N),
+     $      HEAD (N), PINV (N), LEN (N), AP (N+1), AI (NZ), IW (IWLEN)
+        CHARACTER A (24,24)
+
+        DATA AP
+     $      / 1, 9, 14, 19, 24, 29, 34, 42, 50, 53, 61, 66, 71,
+     $       76, 81, 86, 91, 94, 102, 110, 118, 123, 131, 134, 137 /
+        DATA AI /
+     $      6, 7, 13, 14, 18, 19, 20, 22,
+     $      9, 10, 14, 15, 18,
+     $      7, 12, 21, 22, 23,
+     $      8, 11, 16, 19, 20,
+     $      8, 10, 15, 16, 17,
+     $      1, 7, 13, 14, 18,
+     $      1, 3, 6, 12, 13, 20, 22, 24,
+     $      4, 5, 10, 15, 16, 17, 18, 19,
+     $      2, 10, 15,
+     $      2, 5, 8, 9, 14, 15, 18, 19,
+     $      4, 19, 20, 21, 22,
+     $      3, 7, 13, 22, 24,
+     $      1, 6, 7, 12, 24,
+     $      1, 2, 6, 10, 18,
+     $      2, 5, 8, 9, 10,
+     $      4, 5, 8, 17, 19,
+     $      5, 8, 16,
+     $      1, 2, 6, 8, 10, 14, 19, 20,
+     $      1, 4, 8, 10, 11, 16, 18, 20,
+     $      1, 4, 7, 11, 18, 19, 21, 22,
+     $      3, 11, 20, 22, 23,
+     $      1, 3, 7, 11, 12, 20, 21, 23,
+     $      3, 21, 22,
+     $      7, 12, 13 /
+
+C       print the input matrix
+        PRINT 11, N, N, NZ
+11      FORMAT ('AMD Fortran 77 demo, with the 24-by-24',
+     $      ' Harwell/Boeing matrix, can_24:'
+     $      /, 'Input matrix: ', I2, '-by-', I2,' with ',I3,' entries',
+     $      /, 'Note that the Fortran version of AMD requires that'
+     $      /, 'no diagonal entries be present.')
+        DO 20 J = 1, N
+            PRINT 21, J, AP (J+1) - AP (J), AP (J), AP (J+1)-1
+21          FORMAT ( /, 'Column: ', I2, ' number of entries: ', I2,
+     $          ' with row indices in AI (', I3, ' ... ', I3, ')')
+            PRINT 10, ((AI (P)), P = AP (J), AP (J+1) - 1)
+10          FORMAT ('    row indices: ', 24I3)
+20      CONTINUE
+
+C       print a character plot of the input matrix.  This is only
+C       reasonable because the matrix is small.
+        PRINT 31
+31      FORMAT ('Plot of input matrix pattern:')
+        DO 50 J = 1,N
+            DO 30 I = 1,N
+                A (I, J) = '.'
+30          CONTINUE
+C           add the diagonal entry to the plot
+            A (J, J) = 'X'
+            DO 40 P = AP (J), AP (J+1) - 1
+                I = AI (P)
+                A (I, J) = 'X'
+40          CONTINUE
+50      CONTINUE
+        PRINT 60, ((MOD (J, 10)), J = 1,N)
+60      FORMAT ('     ', 24I2)
+        DO 80 I = 1,N
+            PRINT 70, I, (A (I, J), J = 1,N)
+70          FORMAT (' ', I2, ': ', 24A2)
+80      CONTINUE
+
+        DO 190 METHOD = 1,2
+
+C           load the matrix into AMD's workspace
+            DO 90 J = 1,N
+                PE (J) = AP (J)
+                LEN (J) = AP (J+1) - AP (J)
+90          CONTINUE
+            DO 100 P = 1,NZ
+                IW (P) = AI (P)
+100         CONTINUE
+            PFREE = NZ + 1
+
+C           order the matrix using AMD or AMDBAR
+            IF (METHOD .EQ. 1) THEN
+                PRINT 101 
+101             FORMAT (/, '------------------------------------------',
+     $                  /, 'ordering the matrix with AMD',
+     $                  /, '------------------------------------------')
+                CALL AMD (N, PE, IW, LEN, IWLEN, PFREE, NV, NEXT,
+     $              PERM, HEAD, PINV, DEGREE, NCMPA, W)
+            ELSE
+                PRINT 102 
+102             FORMAT (/, '------------------------------------------',
+     $                  /, 'ordering the matrix with AMDBAR',
+     $                  /, '------------------------------------------')
+                CALL AMDBAR (N, PE, IW, LEN, IWLEN, PFREE, NV, NEXT,
+     $              PERM, HEAD, PINV, DEGREE, NCMPA, W)
+            ENDIF
+
+C           print the permutation vector, PERM, and its inverse, PINV.
+C           row/column J = PERM (K) is the Kth row/column in the
+C           permuted matrix.
+            PRINT 110, (PERM (K), K = 1,N)
+110         FORMAT (/, 'Permutation vector: ', /, 24I3)
+            PRINT 120, (PINV (J), J = 1,N)
+120         FORMAT (/, 'Inverse permutation vector: ', /, 24I3)
+
+C           print a character plot of the permuted matrix.
+            PRINT 121
+121         FORMAT ('Plot of permuted matrix pattern:')
+            DO 150 JNEW = 1,N
+                J = PERM (JNEW)
+                DO 130 INEW = 1,N
+                    A (INEW, JNEW) = '.'
+130             CONTINUE
+C               add the diagonal entry to the plot
+                A (JNEW, JNEW) = 'X'
+                DO 140 P = AP (J), AP (J+1) - 1
+                    INEW = PINV (AI (P))
+                    A (INEW, JNEW) = 'X'
+140             CONTINUE
+150         CONTINUE
+            PRINT 60, ((MOD (J, 10)), J = 1,N)
+            DO 160 I = 1,N
+                PRINT 70, I, (A (I, J), J = 1,N)
+160         CONTINUE
+
+C           print the permuted matrix, PERM*A*PERM'
+            DO 180 JNEW = 1,N
+                J = PERM (JNEW)
+                PRINT 171, JNEW, J, AP (J+1) - AP (J)
+171             FORMAT (/, 'New column: ', I2, ' old column: ', I2,
+     $              ' number of entries: ', I2)
+                PRINT 170, (PINV (AI (P)), P = AP (J), AP (J+1) - 1)
+170             FORMAT ('    new row indices: ', 24I3)
+180         CONTINUE
+190     CONTINUE
+        END
diff --git a/deal.II/contrib/umfpack/AMD/Demo/amd_f77demo.out b/deal.II/contrib/umfpack/AMD/Demo/amd_f77demo.out
new file mode 100644 (file)
index 0000000..10758dd
--- /dev/null
@@ -0,0 +1,318 @@
+AMD Fortran 77 demo, with the 24-by-24 Harwell/Boeing matrix, can_24:
+Input matrix: 24-by-24 with 136 entries
+Note that the Fortran version of AMD requires that
+no diagonal entries be present.
+
+Column:  1 number of entries:  8 with row indices in AI (  1 ...   8)
+    row indices:   6  7 13 14 18 19 20 22
+
+Column:  2 number of entries:  5 with row indices in AI (  9 ...  13)
+    row indices:   9 10 14 15 18
+
+Column:  3 number of entries:  5 with row indices in AI ( 14 ...  18)
+    row indices:   7 12 21 22 23
+
+Column:  4 number of entries:  5 with row indices in AI ( 19 ...  23)
+    row indices:   8 11 16 19 20
+
+Column:  5 number of entries:  5 with row indices in AI ( 24 ...  28)
+    row indices:   8 10 15 16 17
+
+Column:  6 number of entries:  5 with row indices in AI ( 29 ...  33)
+    row indices:   1  7 13 14 18
+
+Column:  7 number of entries:  8 with row indices in AI ( 34 ...  41)
+    row indices:   1  3  6 12 13 20 22 24
+
+Column:  8 number of entries:  8 with row indices in AI ( 42 ...  49)
+    row indices:   4  5 10 15 16 17 18 19
+
+Column:  9 number of entries:  3 with row indices in AI ( 50 ...  52)
+    row indices:   2 10 15
+
+Column: 10 number of entries:  8 with row indices in AI ( 53 ...  60)
+    row indices:   2  5  8  9 14 15 18 19
+
+Column: 11 number of entries:  5 with row indices in AI ( 61 ...  65)
+    row indices:   4 19 20 21 22
+
+Column: 12 number of entries:  5 with row indices in AI ( 66 ...  70)
+    row indices:   3  7 13 22 24
+
+Column: 13 number of entries:  5 with row indices in AI ( 71 ...  75)
+    row indices:   1  6  7 12 24
+
+Column: 14 number of entries:  5 with row indices in AI ( 76 ...  80)
+    row indices:   1  2  6 10 18
+
+Column: 15 number of entries:  5 with row indices in AI ( 81 ...  85)
+    row indices:   2  5  8  9 10
+
+Column: 16 number of entries:  5 with row indices in AI ( 86 ...  90)
+    row indices:   4  5  8 17 19
+
+Column: 17 number of entries:  3 with row indices in AI ( 91 ...  93)
+    row indices:   5  8 16
+
+Column: 18 number of entries:  8 with row indices in AI ( 94 ... 101)
+    row indices:   1  2  6  8 10 14 19 20
+
+Column: 19 number of entries:  8 with row indices in AI (102 ... 109)
+    row indices:   1  4  8 10 11 16 18 20
+
+Column: 20 number of entries:  8 with row indices in AI (110 ... 117)
+    row indices:   1  4  7 11 18 19 21 22
+
+Column: 21 number of entries:  5 with row indices in AI (118 ... 122)
+    row indices:   3 11 20 22 23
+
+Column: 22 number of entries:  8 with row indices in AI (123 ... 130)
+    row indices:   1  3  7 11 12 20 21 23
+
+Column: 23 number of entries:  3 with row indices in AI (131 ... 133)
+    row indices:   3 21 22
+
+Column: 24 number of entries:  3 with row indices in AI (134 ... 136)
+    row indices:   7 12 13
+Plot of input matrix pattern:
+      1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4
+  1:  X . . . . X X . . . . . X X . . . X X X . X . .
+  2:  . X . . . . . . X X . . . X X . . X . . . . . .
+  3:  . . X . . . X . . . . X . . . . . . . . X X X .
+  4:  . . . X . . . X . . X . . . . X . . X X . . . .
+  5:  . . . . X . . X . X . . . . X X X . . . . . . .
+  6:  X . . . . X X . . . . . X X . . . X . . . . . .
+  7:  X . X . . X X . . . . X X . . . . . . X . X . X
+  8:  . . . X X . . X . X . . . . X X X X X . . . . .
+  9:  . X . . . . . . X X . . . . X . . . . . . . . .
+ 10:  . X . . X . . X X X . . . X X . . X X . . . . .
+ 11:  . . . X . . . . . . X . . . . . . . X X X X . .
+ 12:  . . X . . . X . . . . X X . . . . . . . . X . X
+ 13:  X . . . . X X . . . . X X . . . . . . . . . . X
+ 14:  X X . . . X . . . X . . . X . . . X . . . . . .
+ 15:  . X . . X . . X X X . . . . X . . . . . . . . .
+ 16:  . . . X X . . X . . . . . . . X X . X . . . . .
+ 17:  . . . . X . . X . . . . . . . X X . . . . . . .
+ 18:  X X . . . X . X . X . . . X . . . X X X . . . .
+ 19:  X . . X . . . X . X X . . . . X . X X X . . . .
+ 20:  X . . X . . X . . . X . . . . . . X X X X X . .
+ 21:  . . X . . . . . . . X . . . . . . . . X X X X .
+ 22:  X . X . . . X . . . X X . . . . . . . X X X X .
+ 23:  . . X . . . . . . . . . . . . . . . . . X X X .
+ 24:  . . . . . . X . . . . X X . . . . . . . . . . X
+
+------------------------------------------
+ordering the matrix with AMD
+------------------------------------------
+
+Permutation vector: 
+ 24 23 17  9 15  5 21 13  6 11 16  8  2 10 14 18  1  3  4 19  7 12 22 20
+
+Inverse permutation vector: 
+ 17 13 18 19  6  9 21 12  4 14 10 22  8 15  5 11  3 16 20 24  7 23  2  1
+Plot of permuted matrix pattern:
+      1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4
+  1:  X . . . . . . X . . . . . . . . . . . . X X . .
+  2:  . X . . . . X . . . . . . . . . . X . . . . X .
+  3:  . . X . . X . . . . X X . . . . . . . . . . . .
+  4:  . . . X X . . . . . . . X X . . . . . . . . . .
+  5:  . . . X X X . . . . . X X X . . . . . . . . . .
+  6:  . . X . X X . . . . X X . X . . . . . . . . . .
+  7:  . X . . . . X . . X . . . . . . . X . . . . X X
+  8:  X . . . . . . X X . . . . . . . X . . . X X . .
+  9:  . . . . . . . X X . . . . . X X X . . . X . . .
+ 10:  . . . . . . X . . X . . . . . . . . X X . . X X
+ 11:  . . X . . X . . . . X X . . . . . . X X . . . .
+ 12:  . . X . X X . . . . X X . X . X . . X X . . . .
+ 13:  . . . X X . . . . . . . X X X X . . . . . . . .
+ 14:  . . . X X X . . . . . X X X X X . . . X . . . .
+ 15:  . . . . . . . . X . . . X X X X X . . . . . . .
+ 16:  . . . . . . . . X . . X X X X X X . . X . . . X
+ 17:  . . . . . . . X X . . . . . X X X . . X X . X X
+ 18:  . X . . . . X . . . . . . . . . . X . . X X X .
+ 19:  . . . . . . . . . X X X . . . . . . X X . . . X
+ 20:  . . . . . . . . . X X X . X . X X . X X . . . X
+ 21:  X . . . . . . X X . . . . . . . X X . . X X X X
+ 22:  X . . . . . . X . . . . . . . . . X . . X X X .
+ 23:  . X . . . . X . . X . . . . . . X X . . X X X X
+ 24:  . . . . . . X . . X . . . . . X X . X X X . X X
+
+New column:  1 old column: 24 number of entries:  3
+    new row indices:  21 22  8
+
+New column:  2 old column: 23 number of entries:  3
+    new row indices:  18  7 23
+
+New column:  3 old column: 17 number of entries:  3
+    new row indices:   6 12 11
+
+New column:  4 old column:  9 number of entries:  3
+    new row indices:  13 14  5
+
+New column:  5 old column: 15 number of entries:  5
+    new row indices:  13  6 12  4 14
+
+New column:  6 old column:  5 number of entries:  5
+    new row indices:  12 14  5 11  3
+
+New column:  7 old column: 21 number of entries:  5
+    new row indices:  18 10 24 23  2
+
+New column:  8 old column: 13 number of entries:  5
+    new row indices:  17  9 21 22  1
+
+New column:  9 old column:  6 number of entries:  5
+    new row indices:  17 21  8 15 16
+
+New column: 10 old column: 11 number of entries:  5
+    new row indices:  19 20 24  7 23
+
+New column: 11 old column: 16 number of entries:  5
+    new row indices:  19  6 12  3 20
+
+New column: 12 old column:  8 number of entries:  8
+    new row indices:  19  6 14  5 11  3 16 20
+
+New column: 13 old column:  2 number of entries:  5
+    new row indices:   4 14 15  5 16
+
+New column: 14 old column: 10 number of entries:  8
+    new row indices:  13  6 12  4 15  5 16 20
+
+New column: 15 old column: 14 number of entries:  5
+    new row indices:  17 13  9 14 16
+
+New column: 16 old column: 18 number of entries:  8
+    new row indices:  17 13  9 12 14 15 20 24
+
+New column: 17 old column:  1 number of entries:  8
+    new row indices:   9 21  8 15 16 20 24 23
+
+New column: 18 old column:  3 number of entries:  5
+    new row indices:  21 22  7 23  2
+
+New column: 19 old column:  4 number of entries:  5
+    new row indices:  12 10 11 20 24
+
+New column: 20 old column: 19 number of entries:  8
+    new row indices:  17 19 12 14 10 11 16 24
+
+New column: 21 old column:  7 number of entries:  8
+    new row indices:  17 18  9 22  8 24 23  1
+
+New column: 22 old column: 12 number of entries:  5
+    new row indices:  18 21  8 23  1
+
+New column: 23 old column: 22 number of entries:  8
+    new row indices:  17 18 21 10 22 24  7  2
+
+New column: 24 old column: 20 number of entries:  8
+    new row indices:  17 19 21 10 16 20  7 23
+
+------------------------------------------
+ordering the matrix with AMDBAR
+------------------------------------------
+
+Permutation vector: 
+ 24 23 17  9 15  5 21 13  6 11 16  8  2 10 14 18  1  3  4 19  7 12 22 20
+
+Inverse permutation vector: 
+ 17 13 18 19  6  9 21 12  4 14 10 22  8 15  5 11  3 16 20 24  7 23  2  1
+Plot of permuted matrix pattern:
+      1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4
+  1:  X . . . . . . X . . . . . . . . . . . . X X . .
+  2:  . X . . . . X . . . . . . . . . . X . . . . X .
+  3:  . . X . . X . . . . X X . . . . . . . . . . . .
+  4:  . . . X X . . . . . . . X X . . . . . . . . . .
+  5:  . . . X X X . . . . . X X X . . . . . . . . . .
+  6:  . . X . X X . . . . X X . X . . . . . . . . . .
+  7:  . X . . . . X . . X . . . . . . . X . . . . X X
+  8:  X . . . . . . X X . . . . . . . X . . . X X . .
+  9:  . . . . . . . X X . . . . . X X X . . . X . . .
+ 10:  . . . . . . X . . X . . . . . . . . X X . . X X
+ 11:  . . X . . X . . . . X X . . . . . . X X . . . .
+ 12:  . . X . X X . . . . X X . X . X . . X X . . . .
+ 13:  . . . X X . . . . . . . X X X X . . . . . . . .
+ 14:  . . . X X X . . . . . X X X X X . . . X . . . .
+ 15:  . . . . . . . . X . . . X X X X X . . . . . . .
+ 16:  . . . . . . . . X . . X X X X X X . . X . . . X
+ 17:  . . . . . . . X X . . . . . X X X . . X X . X X
+ 18:  . X . . . . X . . . . . . . . . . X . . X X X .
+ 19:  . . . . . . . . . X X X . . . . . . X X . . . X
+ 20:  . . . . . . . . . X X X . X . X X . X X . . . X
+ 21:  X . . . . . . X X . . . . . . . X X . . X X X X
+ 22:  X . . . . . . X . . . . . . . . . X . . X X X .
+ 23:  . X . . . . X . . X . . . . . . X X . . X X X X
+ 24:  . . . . . . X . . X . . . . . X X . X X X . X X
+
+New column:  1 old column: 24 number of entries:  3
+    new row indices:  21 22  8
+
+New column:  2 old column: 23 number of entries:  3
+    new row indices:  18  7 23
+
+New column:  3 old column: 17 number of entries:  3
+    new row indices:   6 12 11
+
+New column:  4 old column:  9 number of entries:  3
+    new row indices:  13 14  5
+
+New column:  5 old column: 15 number of entries:  5
+    new row indices:  13  6 12  4 14
+
+New column:  6 old column:  5 number of entries:  5
+    new row indices:  12 14  5 11  3
+
+New column:  7 old column: 21 number of entries:  5
+    new row indices:  18 10 24 23  2
+
+New column:  8 old column: 13 number of entries:  5
+    new row indices:  17  9 21 22  1
+
+New column:  9 old column:  6 number of entries:  5
+    new row indices:  17 21  8 15 16
+
+New column: 10 old column: 11 number of entries:  5
+    new row indices:  19 20 24  7 23
+
+New column: 11 old column: 16 number of entries:  5
+    new row indices:  19  6 12  3 20
+
+New column: 12 old column:  8 number of entries:  8
+    new row indices:  19  6 14  5 11  3 16 20
+
+New column: 13 old column:  2 number of entries:  5
+    new row indices:   4 14 15  5 16
+
+New column: 14 old column: 10 number of entries:  8
+    new row indices:  13  6 12  4 15  5 16 20
+
+New column: 15 old column: 14 number of entries:  5
+    new row indices:  17 13  9 14 16
+
+New column: 16 old column: 18 number of entries:  8
+    new row indices:  17 13  9 12 14 15 20 24
+
+New column: 17 old column:  1 number of entries:  8
+    new row indices:   9 21  8 15 16 20 24 23
+
+New column: 18 old column:  3 number of entries:  5
+    new row indices:  21 22  7 23  2
+
+New column: 19 old column:  4 number of entries:  5
+    new row indices:  12 10 11 20 24
+
+New column: 20 old column: 19 number of entries:  8
+    new row indices:  17 19 12 14 10 11 16 24
+
+New column: 21 old column:  7 number of entries:  8
+    new row indices:  17 18  9 22  8 24 23  1
+
+New column: 22 old column: 12 number of entries:  5
+    new row indices:  18 21  8 23  1
+
+New column: 23 old column: 22 number of entries:  8
+    new row indices:  17 18 21 10 22 24  7  2
+
+New column: 24 old column: 20 number of entries:  8
+    new row indices:  17 19 21 10 16 20  7 23
diff --git a/deal.II/contrib/umfpack/AMD/Demo/amd_f77simple.f b/deal.II/contrib/umfpack/AMD/Demo/amd_f77simple.f
new file mode 100644 (file)
index 0000000..ef189fb
--- /dev/null
@@ -0,0 +1,38 @@
+C ----------------------------------------------------------------------
+C AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A.
+C Davis, Patrick R. Amestoy, and Iain S. Duff.  See ../README for
+C License.  email: davis@cise.ufl.edu    CISE Department, Univ. of
+C Florida.  web: http://www.cise.ufl.edu/research/sparse/amd
+C ----------------------------------------------------------------------
+
+C This program provides an example of how to call the Fortran version
+C of AMD.  It uses the same matrix as the amd_simple.c demo (in C).
+C Note that the diagonal entries are not present, and the matrix is
+C symmetric.
+
+        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
diff --git a/deal.II/contrib/umfpack/AMD/Demo/amd_f77simple.out b/deal.II/contrib/umfpack/AMD/Demo/amd_f77simple.out
new file mode 100644 (file)
index 0000000..c7f902e
--- /dev/null
@@ -0,0 +1,5 @@
+P ( 1) =  4
+P ( 2) =  1
+P ( 3) =  3
+P ( 4) =  5
+P ( 5) =  2
diff --git a/deal.II/contrib/umfpack/AMD/Demo/amd_f77wrapper.c b/deal.II/contrib/umfpack/AMD/Demo/amd_f77wrapper.c
new file mode 100644 (file)
index 0000000..01802b8
--- /dev/null
@@ -0,0 +1,108 @@
+/* ========================================================================= */
+/* === amd_f77wrapper ====================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,  */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README for License.         */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.           */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* Fortran interface for the C-callable AMD library (int version only).  This
+ * is HIGHLY non-portable.  You will need to modify this depending on how your
+ * Fortran and C compilers behave.  Two examples are provided.
+ *
+ * To avoid using I/O, and to avoid the extra porting step of a Fortran
+ * function, the status code is returned as the first entry in P (P [0] in C
+ * and P (1) in Fortran) if an error occurs.  The error codes are negative
+ * (-1: out of memory, -2: invalid matrix).
+ *
+ * For some C and Fortran compilers, the Fortran compiler appends a single "_"
+ * after each routine name.  C doesn't do this, so the translation is made
+ * here.  Some Fortran compilers don't append an underscore (xlf on IBM AIX,
+ * for * example).
+ *
+ * Tested with the following compilers:
+ * Solaris with cc and f77 from Sun WorkShop 6 update 1.
+ * SGI Irix with MIPSpro cc and f77 compilers version 7.4
+ * Linux with GNU gcc or Intel's icc, and GNU g77 Intel's ifc Fortran compiler.
+ *     (any combination).  Note that with g77, a call to amd_order in Fortran
+ *     gets translated to a call to amd_order__, with two underscores ("_").
+ *     Thus, the Fortran names do not include an underscore.
+ */
+
+#include "amd.h"
+#include <stdio.h>
+
+/* ------------------------------------------------------------------------- */
+/* Linux, Solaris, SGI */
+/* ------------------------------------------------------------------------- */
+
+void amdorder_ (int *n, const int *Ap, const int *Ai, int *P,
+    double *Control, double *Info)
+{
+    int result = amd_order (*n, Ap, Ai, P, Control, Info) ;
+    if (result != AMD_OK && P) P [0] = result ;
+}
+
+void amddefaults_ (double *Control)
+{
+    amd_defaults (Control) ;
+}
+
+void amdcontrol_ (double *Control)
+{
+    fflush (stdout) ;
+    amd_control (Control) ;
+    fflush (stdout) ;
+}
+
+void amdinfo_ (double *Info)
+{
+    fflush (stdout) ;
+    amd_info (Info) ;
+    fflush (stdout) ;
+}
+
+void amdpreproc_ (int *n, const int *Ap, const int *Ai, int *Rp, int *Ri)
+{
+    int result = amd_preprocess (*n, Ap, Ai, Rp, Ri) ;
+    if (result != AMD_OK && Rp) Rp [0] = result ;
+}
+
+/* ------------------------------------------------------------------------- */
+/* IBM AIX.  Probably Windows, Compaq Alpha, and HP Unix as well. */
+/* ------------------------------------------------------------------------- */
+
+void amdorder (int *n, const int *Ap, const int *Ai, int *P,
+    double *Control, double *Info)
+{
+    int result = amd_order (*n, Ap, Ai, P, Control, Info) ;
+    if (result != AMD_OK && P) P [0] = result ;
+}
+
+void amddefaults (double *Control)
+{
+    amd_defaults (Control) ;
+}
+
+void amdcontrol (double *Control)
+{
+    fflush (stdout) ;
+    amd_control (Control) ;
+    fflush (stdout) ;
+}
+
+void amdinfo (double *Info)
+{
+    fflush (stdout) ;
+    amd_info (Info) ;
+    fflush (stdout) ;
+}
+
+void amdpreproc (int *n, const int *Ap, const int *Ai, int *Rp, int *Ri)
+{
+    int result = amd_preprocess (*n, Ap, Ai, Rp, Ri) ;
+    if (result != AMD_OK && Rp) Rp [0] = result ;
+}
diff --git a/deal.II/contrib/umfpack/AMD/Demo/amd_simple.c b/deal.II/contrib/umfpack/AMD/Demo/amd_simple.c
new file mode 100644 (file)
index 0000000..2399526
--- /dev/null
@@ -0,0 +1,23 @@
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,  */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README for License.         */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.           */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+#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) ;
+}
+
diff --git a/deal.II/contrib/umfpack/AMD/Demo/amd_simple.out b/deal.II/contrib/umfpack/AMD/Demo/amd_simple.out
new file mode 100644 (file)
index 0000000..08a04e0
--- /dev/null
@@ -0,0 +1,5 @@
+P [0] = 0
+P [1] = 3
+P [2] = 2
+P [3] = 4
+P [4] = 1
diff --git a/deal.II/contrib/umfpack/AMD/Doc/AMD_UserGuide.bib b/deal.II/contrib/umfpack/AMD/Doc/AMD_UserGuide.bib
new file mode 100644 (file)
index 0000000..9584598
--- /dev/null
@@ -0,0 +1,86 @@
+@string{SIREV       = "{SIAM} Review"}
+@string{SIMAX       = "{SIAM} J. Matrix Anal. Applic."}
+@string{SIAMJSC     = "{SIAM} J. Sci. Comput."}
+@string{TOMS        = "{ACM} Trans. Math. Softw."}
+
+@article{schu:01,
+       author    = {J. Schulze},
+       title     = {Towards a tighter coupling of bottom-up and top-down sparse matrix ordering methods},
+       journal   = {BIT},
+       volume    = {41},
+       number    = {4},
+       pages     = "800--841",
+       year      = {2001}
+       }
+
+@article{GeorgeLiu89,
+       author={George, A. and Liu, J. W. H.},
+       year={1989},
+       title={The Evolution of the Minimum Degree Ordering Algorithm},
+       journal=SIREV,
+       volume={31},
+       number={1},
+       pages={1--19}}
+
+@article{AmestoyDavisDuff96,
+       author={Amestoy, P. R. and Davis, T. A. and Duff, I. S.},
+       title={An approximate minimum degree ordering algorithm},
+       journal=SIMAX,
+       year={1996}
+       ,volume={17}
+       ,number={4}
+       ,pages={886-905}
+       }
+
+@misc{hsl:2002,
+ author = {HSL},
+  title = "{HSL} 2002: {A} collection of {F}ortran codes for large
+           scale scientific computation",
+  note = {{\tt www.cse.clrc.ac.uk/nag/hsl}},
+  year = 2002}
+
+
+@article{RothbergEisenstat98,
+       author={Rothberg, E. and Eisenstat, S. C.},
+       title={Node selection strategies for bottom-up sparse matrix orderings},
+       journal=SIMAX,
+       year={1998}
+       ,volume={19}
+       ,number={3}
+       ,pages={682-695}
+       }
+
+@article{KarypisKumar98e,
+       author={Karypis, G. and Kumar, V.},
+       title={A fast and high quality multilevel scheme for partitioning irregular graphs},
+       journal=SIAMJSC,
+       year={1998}
+       ,volume={20}
+       ,pages={359-392}
+       }
+
+@article{Chaco,
+       author={B. Hendrickson and E. Rothberg},
+       title={Improving the runtime and quality of nested dissection ordering},
+       journal=SIAMJSC,
+       year={1999}
+       ,volume={20}
+       ,pages={468--489}
+       }
+
+@article{PellegriniRomanAmestoy00,
+       author={Pellegrini, F. and Roman, J. and Amestoy, P.},
+       title={Hybridizing nested dissection and halo approximate minimum degree for efficient sparse matrix ordering},
+       journal={Concurrency: Practice and Experience},
+       year={2000}
+       ,volume={12}
+       ,pages={68-84}
+       }
+
+@article{DavisGilbertLarimoreNg00pending,
+       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={(to appear)}
+       }
+
diff --git a/deal.II/contrib/umfpack/AMD/Doc/AMD_UserGuide.pdf b/deal.II/contrib/umfpack/AMD/Doc/AMD_UserGuide.pdf
new file mode 100644 (file)
index 0000000..39ca0b2
Binary files /dev/null and b/deal.II/contrib/umfpack/AMD/Doc/AMD_UserGuide.pdf differ
diff --git a/deal.II/contrib/umfpack/AMD/Doc/AMD_UserGuide.tex b/deal.II/contrib/umfpack/AMD/Doc/AMD_UserGuide.tex
new file mode 100644 (file)
index 0000000..8e4d67b
--- /dev/null
@@ -0,0 +1,1138 @@
+\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 1.1 User Guide}
+\author{Patrick R. Amestoy\thanks{ENSEEIHT-IRIT,
+2 rue Camichel 31017 Toulouse, France.
+email: amestoy@enseeiht.fr.  http://www.enseeiht.fr/$\sim$amestoy.}
+\and Timothy A. Davis\thanks{
+Dept.~of Computer and Information Science and Engineering,
+Univ.~of Florida, Gainesville, FL, USA.
+email: davis@cise.ufl.edu.
+http://www.cise.ufl.edu/$\sim$davis.
+This work was supported by the National
+Science Foundation, under grants ASC-9111263, DMS-9223088, and CCR-0203270.
+Portions of the work were done while on sabbatical at Stanford University
+and Lawrence Berkeley National Laboratory (with funding from Stanford
+University and the SciDAC program).
+}
+\and Iain S. Duff\thanks{Rutherford Appleton Laboratory, Chilton, Didcot, 
+Oxon OX11 0QX, England. email: i.s.duff@rl.ac.uk.  
+http://www.numerical.rl.ac.uk/people/isd/isd.html.
+This work was supported by the EPSRC under grant GR/R46441.
+}}
+
+\date{January 29, 2004}
+\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, CISE Department, University of Florida,
+Gainesville, FL, 2004.
+
+AMD Version 1.1 (Jan. 21, 2004), Copyright\copyright 2004 by Timothy A.
+Davis, Patrick R. Amestoy, and Iain S. Duff.  All Rights Reserved.
+
+{\bf AMD License:}
+    Your use or distribution of AMD or any modified version of
+    AMD implies that you agree to this License.
+
+    THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
+    EXPRESSED OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+
+    Permission is hereby granted to use or copy this program, provided
+    that the Copyright, this License, and the Availability of the original
+    version is retained on all copies.  User documentation of any code that
+    uses AMD or any modified version of AMD code must cite the
+    Copyright, this License, the Availability note, and ``Used by permission.''
+    Permission to modify the code and to distribute modified code is granted,
+    provided the Copyright, this License, and the Availability note are
+    retained, and a notice that the code was modified is included.  This
+    software was developed with support from the National Science Foundation,
+    and is provided to you free of charge.
+
+{\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} 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 1.1 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}
+%------------------------------------------------------------------------------
+
+To use AMD in MATLAB, you must first compile the AMD mexFunction.
+Just type {\tt make} in the Unix system shell, while in the {\tt AMD}
+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
+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{DavisGilbertLarimoreNg00pending}.
+
+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 five 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\_INVALID} if
+    the matrix is invalid, or {\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\_preprocess}
+({\tt long} version: {\tt amd\_l\_info})
+    {\footnotesize
+    \begin{verbatim}
+    #include "amd.h"
+    int n, Ap [n+1], Ai [nz], Rp [n+1], Ri [nz] ;
+    int result = amd_preprocess (n, Ap, Ai, Rp, Ri) ;
+    \end{verbatim}
+    }
+    Removes duplicate entries and sorts each column of its input $\m{A}$,
+    and returns the nonzero pattern of the transpose, $\m{R}=\m{A}\tr$.
+    It returns the transpose because this is the simplest way to sort
+    a matrix and remove duplicate entries.  Either $\m{A}$ or $\m{A}\tr$
+    can be passed to {\tt amd\_order} with little effect on the
+    ordering (except for minor tie-breaking changes).
+
+\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},
+no duplicate row indices may be present, and the row indices in any given
+column must be sorted in ascending order.
+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),
+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.
+
+The input to {\tt amd\_order} must have sorted columns because it uses
+an in-place algorithm to construct $\m{A}+\m{A}\tr$ without first constructing
+$\m{A}\tr$.  This saves memory, but places an additional restriction on
+the input.  If the input matrix has columns with unsorted and/or duplicate
+row indices, it is not valid as input to {\tt amd\_order}.  To handle this
+case, the {\tt amd\_preprocess} routine is provided.  It sorts, transposes,
+and removes duplicate entries from its input matrix, returning its result
+as another compressed-column matrix $\m{R}$ which can then be passed to
+{\tt amd\_order}.
+
+%------------------------------------------------------------------------------
+\subsection{Control parameters}
+\label{control_param}
+%------------------------------------------------------------------------------
+
+Control parameters are set 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}
+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], Rp [n+1], Ri [nz] ;
+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) ;
+amd_preprocess (n, Ap, Ai, Rp, Ri) ;
+\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], Rp [n+1], Ri [nz] ;
+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) ;
+amd_l_preprocess (n, Ap, Ai, Rp, Ri) ;
+\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 AMD/Make}
+directory.  You can edit the {\tt Make.include}
+file in that directory 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}.
+Two 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.  The AMD mexFunction for
+use in MATLAB will also be compiled.  If you do not have MATLAB
+type {\tt make lib} instead.
+
+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} removes all files not in the
+original distribution.
+If you compile AMD and then later change the {\tt Make.include}
+file or your system-specific configuration file such as {\tt Make.linux},
+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 Make.include} 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 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 Make.include} includes some definitions regarding the BLAS.
+This is so that AMD and UMFPACK (which requires AMD) can share
+the same configuration files.  If you wish to use AMD only, then
+you can ignore any references to the BLAS (the -DNBLAS compile flag).
+
+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 AMD 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.
+
+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.  The {\tt amd\_preprocess.c} file is optional as well, if you
+can ensure that the input matrix to {\tt amd\_order} is always sorted
+and has no duplicate entries.
+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.  Thus, it too can be excluded
+if compiled into a larger production program or library.
+The bare minimum files required to use just {\tt amd\_order} are
+{\tt amd.h} in the {\tt Include} directory,
+and
+{\tt amd\_1.c},
+{\tt amd\_2.c},
+{\tt amd\_aat.c},
+{\tt and\_order.c},
+{\tt amd\_postorder.c},
+{\tt amd\_post\_tree.c},
+{\tt amd\_valid.c},
+and
+{\tt amd\_internal.h},
+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 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,  */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README for License.         */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.           */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* AMD finds a symmetric ordering P of a matrix A so that the Cholesky
+ * factorization of P*A*P' has fewer nonzeros and takes less work than the
+ * Cholesky factorization of A.  If A is not symmetric, then it performs its
+ * ordering on the matrix A+A'.  Two sets of user-callable routines are
+ * provided, one for "int" integers and the other for "long" integers.
+ *
+ * The method is based on the approximate minimum degree algorithm, discussed
+ * in Amestoy, Davis, and Duff, "An approximate degree ordering algorithm",
+ * SIAM Journal of Matrix Analysis and Applications, vol. 17, no. 4, pp.
+ * 886-905, 1996.  This package can perform both the AMD ordering (with
+ * aggressive absorption), and the AMDBAR ordering (without aggressive
+ * absorption) discussed in the above paper.  This package differs from the
+ * Fortran codes discussed in the paper:
+ *
+ *      (1) it can ignore "dense" rows and columns, leading to faster run times
+ *      (2) it computes the ordering of A+A' if A is not symmetric
+ *      (3) it is followed by a depth-first post-ordering of the assembly tree
+ *          (or supernodal elimination tree)
+ *
+ * For historical reasons, the Fortran versions, amd.f and amdbar.f, have
+ * been left (nearly) unchanged.  They compute the identical ordering as
+ * described in the above paper.
+ */
+
+#ifndef AMD_H
+#define AMD_H
+
+int amd_order (             /* returns 0 if OK, negative value if error */
+    int n,                  /* A is n-by-n.  n must be >= 0. */
+    const int Ap [ ],       /* column pointers for A, of size n+1 */
+    const int Ai [ ],       /* row indices of A, of size nz = Ap [n] */
+    int P [ ],              /* output permutation, of size n */
+    double Control [ ],     /* input Control settings, of size AMD_CONTROL */
+    double Info [ ]         /* output Info statistics, of size AMD_INFO */
+) ;
+
+long amd_l_order (          /* see above for description of arguments */
+    long n,
+    const long Ap [ ],
+    const long Ai [ ],
+    long P [ ],
+    double Control [ ],
+    double Info [ ]
+) ;
+
+/* Input arguments (not modified):
+ *
+ *      n: the matrix A is n-by-n.
+ *      Ap: an int/long array of size n+1, containing the column pointers of A.
+ *      Ai: an int/long array of size nz, containing the row indices of A,
+ *          where nz = Ap [n].
+ *      Control:  a double array of size AMD_CONTROL, containing control
+ *          parameters.  Defaults are used if Control is NULL.
+ *
+ * Output arguments (not defined on input):
+ *
+ *      P: an int/long array of size n, containing the output permutation. If
+ *          row i is the kth pivot row, then P [k] = i.  In MATLAB notation,
+ *          the reordered matrix is A (P,P).
+ *      Info: a double array of size AMD_INFO, containing statistical
+ *          information.  Ignored if Info is NULL.
+ *
+ * On input, the matrix A is stored in column-oriented form.  The row indices
+ * of nonzero entries in column j are stored in Ai [Ap [j] ... Ap [j+1]-1].
+ * The row indices must appear in ascending order in each column, and there
+ * must not be any duplicate entries.  Row indices must be in the range 0 to
+ * n-1.  Ap [0] must be zero, and thus nz = Ap [n] is the number of nonzeros
+ * in A.  The array Ap is of size n+1, and the array Ai is of size nz = Ap [n].
+ * The matrix does not need to be symmetric, and the diagonal does not need to
+ * be present (if diagonal entries are present, they are ignored except for
+ * the output statistic Info [AMD_NZDIAG]).  The arrays Ai and Ap are not
+ * modified.  This form of the Ap and Ai arrays to represent the nonzero
+ * pattern of the matrix A is the same as that used internally by MATLAB.
+ * If you wish to use a more flexible input structure, please see the
+ * umfpack_*_triplet_to_col routines in the UMFPACK package, at
+ * http://www.cise.ufl.edu/research/sparse/umfpack, or use the amd_preprocess
+ * routine discussed below.
+ *
+ * Restrictions:  n >= 0.  Ap [0] = 0.  Ap [j] <= Ap [j+1] for all j in the
+ *      range 0 to n-1.  nz = Ap [n] >= 0.  For all j in the range 0 to n-1,
+ *      and for all p in the range Ap [j] to Ap [j+1]-2, Ai [p] < Ai [p+1] must
+ *      hold.  Ai [0..nz-1] must be in the range 0 to n-1.  To avoid integer
+ *      overflow, (2.4*nz + 8*n) < INT_MAX / sizeof (int) for must hold for the
+ *      "int" version. (2.4*nz + 8*n) < LONG_MAX / sizeof (long) must hold
+ *      for the "long" version.  Finally, Ai, Ap, and P must not be NULL.  If
+ *      any of these restrictions are not met, AMD returns AMD_INVALID.
+ *
+ * AMD returns:
+ *
+ *      AMD_OK if the matrix is valid and sufficient memory can be allocated to
+ *          perform the ordering.
+ *
+ *      AMD_OUT_OF_MEMORY if not enough memory can be allocated.
+ *
+ *      AMD_INVALID if the input arguments n, Ap, Ai are invalid, or if P is
+ *          NULL.
+ *
+ * The AMD routine first forms the pattern of the matrix A+A', and then
+ * computes a fill-reducing ordering, P.  If P [k] = i, then row/column i of
+ * the original is the kth pivotal row.  In MATLAB notation, the permuted
+ * matrix is A (P,P), except that 0-based indexing is used instead of the
+ * 1-based indexing in MATLAB.
+ *
+ * The Control array is used to set various parameters for AMD.  If a NULL
+ * pointer is passed, default values are used.  The Control array is not
+ * modified.
+ *
+ *      Control [AMD_DENSE]:  controls the threshold for "dense" rows/columns.
+ *          A dense row/column in A+A' can cause AMD to spend a lot of time in
+ *          ordering the matrix.  If Control [AMD_DENSE] >= 0, rows/columns
+ *          with more than Control [AMD_DENSE] * sqrt (n) entries are ignored
+ *          during the ordering, and placed last in the output order.  The
+ *          default value of Control [AMD_DENSE] is 10.  If negative, no
+ *          rows/columns are treated as "dense".  Rows/columns with 16 or
+ *          fewer off-diagonal entries are never considered "dense".
+ *
+ *      Control [AMD_AGGRESSIVE]: controls whether or not to use aggressive
+ *          absorption, in which a prior element is absorbed into the current
+ *          element if is a subset of the current element, even if it is not
+ *          adjacent to the current pivot element (refer to Amestoy, Davis,
+ *          & Duff, 1996, for more details).  The default value is nonzero,
+ *          which means to perform aggressive absorption.  This nearly always
+ *          leads to a better ordering (because the approximate degrees are
+ *          more accurate) and a lower execution time.  There are cases where
+ *          it can lead to a slightly worse ordering, however.  To turn it off,
+ *          set Control [AMD_AGGRESSIVE] to 0.
+ *
+ *      Control [2..4] are not used in the current version, but may be used in
+ *          future versions.
+ *
+ * The Info array provides statistics about the ordering on output.  If it is
+ * not present, the statistics are not returned.  This is not an error
+ * condition.
+ * 
+ *      Info [AMD_STATUS]:  the return value of AMD, either AMD_OK,
+ *          AMD_OUT_OF_MEMORY, or AMD_INVALID.
+ *
+ *      Info [AMD_N]: n, the size of the input matrix
+ *
+ *      Info [AMD_NZ]: the number of nonzeros in A, nz = Ap [n]
+ *
+ *      Info [AMD_SYMMETRY]:  the symmetry of the matrix A.  It is the number
+ *          of "matched" off-diagonal entries divided by the total number of
+ *          off-diagonal entries.  An entry A(i,j) is matched if A(j,i) is also
+ *          an entry, for any pair (i,j) for which i != j.  In MATLAB notation,
+ *              S = spones (A) ;
+ *              B = tril (S, -1) + triu (S, 1) ;
+ *              symmetry = nnz (B & B') / nnz (B) ;
+ *
+ *      Info [AMD_NZDIAG]: the number of entries on the diagonal of A.
+ *
+ *      Info [AMD_NZ_A_PLUS_AT]:  the number of nonzeros in A+A', excluding the
+ *          diagonal.  If A is perfectly symmetric (Info [AMD_SYMMETRY] = 1)
+ *          with a fully nonzero diagonal, then Info [AMD_NZ_A_PLUS_AT] = nz-n
+ *          (the smallest possible value).  If A is perfectly unsymmetric
+ *          (Info [AMD_SYMMETRY] = 0, for an upper triangular matrix, for
+ *          example) with no diagonal, then Info [AMD_NZ_A_PLUS_AT] = 2*nz
+ *          (the largest possible value).
+ *
+ *      Info [AMD_NDENSE]: the number of "dense" rows/columns of A+A' that were
+ *          removed from A prior to ordering.  These are placed last in the
+ *          output order P.
+ *
+ *      Info [AMD_MEMORY]: the amount of memory used by AMD, in bytes.  In the
+ *          current version, this is 1.2 * Info  [AMD_NZ_A_PLUS_AT] + 9*n
+ *          times the size of an integer.  This is at most 2.4nz + 9n.  This
+ *          excludes the size of the input arguments Ai, Ap, and P, which have
+ *          a total size of nz + 2*n + 1 integers.
+ *
+ *      Info [AMD_NCMPA]: the number of garbage collections performed.
+ *
+ *      Info [AMD_LNZ]: the number of nonzeros in L (excluding the diagonal).
+ *          This is a slight upper bound because mass elimination is combined
+ *          with the approximate degree update.  It is a rough upper bound if
+ *          there are many "dense" rows/columns.  The rest of the statistics,
+ *          below, are also slight or rough upper bounds, for the same reasons.
+ *          The post-ordering of the assembly tree might also not exactly
+ *          correspond to a true elimination tree postordering.
+ *
+ *      Info [AMD_NDIV]: the number of divide operations for a subsequent LDL'
+ *          or LU factorization of the permuted matrix A (P,P).
+ *
+ *      Info [AMD_NMULTSUBS_LDL]:  the number of multiply-subtract pairs for a
+ *          subsequent LDL' factorization of A (P,P).
+ *
+ *      Info [AMD_NMULTSUBS_LU]:  the number of multiply-subtract pairs for a
+ *          subsequent LU factorization of A (P,P), assuming that no numerical
+ *          pivoting is required.
+ *
+ *      Info [AMD_DMAX]:  the maximum number of nonzeros in any column of L,
+ *          including the diagonal.
+ *
+ *      Info [14..19] are not used in the current version, but may be used in
+ *          future versions.
+ */    
+
+/* ------------------------------------------------------------------------- */
+/* AMD preprocess */
+/* ------------------------------------------------------------------------- */
+
+/* amd_preprocess: sorts, removes duplicate entries, and transposes the
+ * nonzero pattern of a column-form matrix A, to obtain the matrix R.
+ *
+ * Alternatively, you can consider this routine as constructing a row-form
+ * matrix from a column-form matrix.  Duplicate entries are allowed in A (and
+ * removed in R). The columns of R are sorted.  Checks its input A for errors.
+ *
+ * On input, A can have unsorted columns, and can have duplicate entries.
+ * Ap [0] must still be zero, and Ap must be monotonically nondecreasing.
+ * Row indices must be in the range 0 to n-1.
+ *
+ * On output, if this routine returns AMD_OK, then the matrix R is a valid
+ * input matrix for AMD_order.  It has sorted columns, with no duplicate
+ * entries in each column.  Since AMD_order operates on the matrix A+A', it
+ * can just as easily use A or A', so the transpose has no significant effect
+ * (except for minor tie-breaking, which can lead to a minor effect in the
+ * quality of the ordering).  As an example, compare the output of amd_demo.c
+ * and amd_demo2.c.
+ *
+ * This routine transposes A to get R because that's the simplest way to
+ * sort and remove duplicate entries from a matrix.
+ *
+ * Allocates 2*n integer work arrays, and free's them when done.
+ *
+ * If you wish to call amd_order, but do not know if your matrix has unsorted
+ * columns or duplicate entries, then you can use the following code, which is
+ * fairly efficient.  amd_order will not allocate any internal matrix until
+ * it checks that the input matrix is valid, so the method below is memory-
+ * efficient as well.  This code snippet assumes that Rp and Ri are already
+ * allocated, and are the same size as Ap and Ai respectively.
+
+    result = amd_order (n, p, Ap, Ai, Control, Info) ;
+    if (result == AMD_INVALID)
+    {
+        if (amd_preprocess (n, Ap, Ai, Rp, Ri) == AMD_OK)
+        {
+            result = amd_order (n, p, Rp, Ri, Control, Info) ;
+        }
+    }
+
+ * amd_preprocess will still return AMD_INVALID if any row index in Ai is out
+ * of range or if the Ap array is invalid.  These errors are not corrected by
+ * amd_preprocess since they represent a more serious error that should be
+ * flagged with the AMD_INVALID error code.
+ */ 
+
+int amd_preprocess
+(
+    int n,
+    const int Ap [ ],
+    const int Ai [ ],
+    int Rp [ ],
+    int Ri [ ]
+) ;
+
+long amd_l_preprocess
+(
+    long n,
+    const long Ap [ ],
+    const long Ai [ ],
+    long Rp [ ],
+    long Ri [ ]
+) ;
+
+/* Input arguments (not modified):
+ *
+ *      n: the matrix A is n-by-n.
+ *      Ap: an int/long array of size n+1, containing the column pointers of A.
+ *      Ai: an int/long array of size nz, containing the row indices of A,
+ *          where nz = Ap [n].
+ *      The nonzero pattern of column j of A is in Ai [Ap [j] ... Ap [j+1]-1].
+ *      Ap [0] must be zero, and Ap [j] <= Ap [j+1] must hold for all j in the
+ *      range 0 to n-1.  Row indices in Ai must be in the range 0 to n-1.
+ *      The row indices in any one column need not be sorted, and duplicates
+ *      may exist.
+ *
+ * Output arguments (not defined on input):
+ *
+ *      Rp: an int/long array of size n+1, containing the column pointers of R.
+ *      Ri: an int/long array of size rnz, containing the row indices of R,
+ *          where rnz = Rp [n].  Note that Rp [n] will be less than Ap [n] if
+ *          duplicates appear in A.  In general, Rp [n] <= Ap [n].
+ *      The data structure for R is the same as A, except that each column of
+ *      R contains sorted row indices, and no duplicates appear in any column.
+ *
+ * amd_preprocess returns:
+ *
+ *      AMD_OK if the matrix A is valid and sufficient memory can be allocated
+ *          to perform the preprocessing.
+ *
+ *      AMD_OUT_OF_MEMORY if not enough memory can be allocated.
+ *
+ *      AMD_INVALID if the input arguments n, Ap, Ai are invalid, or if Rp or
+ *          Ri are NULL.
+ */
+
+/* ------------------------------------------------------------------------- */
+/* 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 */
+#define AMD_INVALID -2          /* input arguments are not valid */
+
+#endif
+\end{verbatim}
+}
+
+%------------------------------------------------------------------------------
+\newpage
+% References
+%------------------------------------------------------------------------------
+
+\bibliographystyle{plain}
+\bibliography{AMD_UserGuide}
+
+\end{document}
diff --git a/deal.II/contrib/umfpack/AMD/Doc/ChangeLog b/deal.II/contrib/umfpack/AMD/Doc/ChangeLog
new file mode 100644 (file)
index 0000000..69c1806
--- /dev/null
@@ -0,0 +1,37 @@
+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/deal.II/contrib/umfpack/AMD/Doc/License b/deal.II/contrib/umfpack/AMD/Doc/License
new file mode 100644 (file)
index 0000000..ed8f2ab
--- /dev/null
@@ -0,0 +1,25 @@
+AMD Version 1.1 (Jan. 21, 2004),  Copyright (c) 2004 by Timothy A.
+Davis, Patrick R. Amestoy, and Iain S. Duff.  All Rights Reserved.
+
+AMD License:
+
+    Your use or distribution of AMD or any modified version of
+    AMD implies that you agree to this License.
+
+    THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
+    EXPRESSED OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+
+    Permission is hereby granted to use or copy this program, provided
+    that the Copyright, this License, and the Availability of the original
+    version is retained on all copies.  User documentation of any code that
+    uses AMD or any modified version of AMD code must cite the
+    Copyright, this License, the Availability note, and "Used by permission."
+    Permission to modify the code and to distribute modified code is granted,
+    provided the Copyright, this License, and the Availability note are
+    retained, and a notice that the code was modified is included.  This
+    software was developed with support from the National Science Foundation,
+    and is provided to you free of charge.
+
+Availability:
+
+    http://www.cise.ufl.edu/research/sparse/amd
diff --git a/deal.II/contrib/umfpack/AMD/Doc/Makefile b/deal.II/contrib/umfpack/AMD/Doc/Makefile
new file mode 100644 (file)
index 0000000..c0cf976
--- /dev/null
@@ -0,0 +1,28 @@
+#------------------------------------------------------------------------------
+# AMD Makefile for compiling on Unix systems (for GNU or original make)
+#------------------------------------------------------------------------------
+
+all: dist
+
+include ../Make/Make.include
+
+#------------------------------------------------------------------------------
+# Remove all but the files in the original distribution
+#------------------------------------------------------------------------------
+
+purge: 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/deal.II/contrib/umfpack/AMD/Include/amd.h b/deal.II/contrib/umfpack/AMD/Include/amd.h
new file mode 100644 (file)
index 0000000..d23c0bb
--- /dev/null
@@ -0,0 +1,359 @@
+/* ========================================================================= */
+/* === AMD:  approximate minimum degree ordering =========================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,  */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README for License.         */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.           */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* AMD finds a symmetric ordering P of a matrix A so that the Cholesky
+ * factorization of P*A*P' has fewer nonzeros and takes less work than the
+ * Cholesky factorization of A.  If A is not symmetric, then it performs its
+ * ordering on the matrix A+A'.  Two sets of user-callable routines are
+ * provided, one for "int" integers and the other for "long" integers.
+ *
+ * The method is based on the approximate minimum degree algorithm, discussed
+ * in Amestoy, Davis, and Duff, "An approximate degree ordering algorithm",
+ * SIAM Journal of Matrix Analysis and Applications, vol. 17, no. 4, pp.
+ * 886-905, 1996.  This package can perform both the AMD ordering (with
+ * aggressive absorption), and the AMDBAR ordering (without aggressive
+ * absorption) discussed in the above paper.  This package differs from the
+ * Fortran codes discussed in the paper:
+ *
+ *     (1) it can ignore "dense" rows and columns, leading to faster run times
+ *     (2) it computes the ordering of A+A' if A is not symmetric
+ *     (3) it is followed by a depth-first post-ordering of the assembly tree
+ *         (or supernodal elimination tree)
+ *
+ * For historical reasons, the Fortran versions, amd.f and amdbar.f, have
+ * been left (nearly) unchanged.  They compute the identical ordering as
+ * described in the above paper.
+ */
+
+#ifndef AMD_H
+#define AMD_H
+
+int amd_order (                    /* returns 0 if OK, negative value if error */
+    int n,                 /* A is n-by-n.  n must be >= 0. */
+    const int Ap [ ],      /* column pointers for A, of size n+1 */
+    const int Ai [ ],      /* row indices of A, of size nz = Ap [n] */
+    int P [ ],             /* output permutation, of size n */
+    double Control [ ],            /* input Control settings, of size AMD_CONTROL */
+    double Info [ ]        /* output Info statistics, of size AMD_INFO */
+) ;
+
+long amd_l_order (         /* see above for description of arguments */
+    long n,
+    const long Ap [ ],
+    const long Ai [ ],
+    long P [ ],
+    double Control [ ],
+    double Info [ ]
+) ;
+
+/* Input arguments (not modified):
+ *
+ *     n: the matrix A is n-by-n.
+ *     Ap: an int/long array of size n+1, containing the column pointers of A.
+ *     Ai: an int/long array of size nz, containing the row indices of A,
+ *         where nz = Ap [n].
+ *     Control:  a double array of size AMD_CONTROL, containing control
+ *         parameters.  Defaults are used if Control is NULL.
+ *
+ * Output arguments (not defined on input):
+ *
+ *     P: an int/long array of size n, containing the output permutation. If
+ *         row i is the kth pivot row, then P [k] = i.  In MATLAB notation,
+ *         the reordered matrix is A (P,P).
+ *     Info: a double array of size AMD_INFO, containing statistical
+ *         information.  Ignored if Info is NULL.
+ *
+ * On input, the matrix A is stored in column-oriented form.  The row indices
+ * of nonzero entries in column j are stored in Ai [Ap [j] ... Ap [j+1]-1].
+ * The row indices must appear in ascending order in each column, and there
+ * must not be any duplicate entries.  Row indices must be in the range 0 to
+ * n-1.  Ap [0] must be zero, and thus nz = Ap [n] is the number of nonzeros
+ * in A.  The array Ap is of size n+1, and the array Ai is of size nz = Ap [n].
+ * The matrix does not need to be symmetric, and the diagonal does not need to
+ * be present (if diagonal entries are present, they are ignored except for
+ * the output statistic Info [AMD_NZDIAG]).  The arrays Ai and Ap are not
+ * modified.  This form of the Ap and Ai arrays to represent the nonzero
+ * pattern of the matrix A is the same as that used internally by MATLAB.
+ * If you wish to use a more flexible input structure, please see the
+ * umfpack_*_triplet_to_col routines in the UMFPACK package, at
+ * http://www.cise.ufl.edu/research/sparse/umfpack, or use the amd_preprocess
+ * routine discussed below.
+ *
+ * Restrictions:  n >= 0.  Ap [0] = 0.  Ap [j] <= Ap [j+1] for all j in the
+ *     range 0 to n-1.  nz = Ap [n] >= 0.  For all j in the range 0 to n-1,
+ *     and for all p in the range Ap [j] to Ap [j+1]-2, Ai [p] < Ai [p+1] must
+ *     hold.  Ai [0..nz-1] must be in the range 0 to n-1.  To avoid integer
+ *     overflow, (2.4*nz + 8*n) < INT_MAX / sizeof (int) for must hold for the
+ *     "int" version. (2.4*nz + 8*n) < LONG_MAX / sizeof (long) must hold
+ *     for the "long" version.  Finally, Ai, Ap, and P must not be NULL.  If
+ *     any of these restrictions are not met, AMD returns AMD_INVALID.
+ *
+ * AMD returns:
+ *
+ *     AMD_OK if the matrix is valid and sufficient memory can be allocated to
+ *         perform the ordering.
+ *
+ *     AMD_OUT_OF_MEMORY if not enough memory can be allocated.
+ *
+ *     AMD_INVALID if the input arguments n, Ap, Ai are invalid, or if P is
+ *         NULL.
+ *
+ * The AMD routine first forms the pattern of the matrix A+A', and then
+ * computes a fill-reducing ordering, P.  If P [k] = i, then row/column i of
+ * the original is the kth pivotal row.  In MATLAB notation, the permuted
+ * matrix is A (P,P), except that 0-based indexing is used instead of the
+ * 1-based indexing in MATLAB.
+ *
+ * The Control array is used to set various parameters for AMD.  If a NULL
+ * pointer is passed, default values are used.  The Control array is not
+ * modified.
+ *
+ *     Control [AMD_DENSE]:  controls the threshold for "dense" rows/columns.
+ *         A dense row/column in A+A' can cause AMD to spend a lot of time in
+ *         ordering the matrix.  If Control [AMD_DENSE] >= 0, rows/columns
+ *         with more than Control [AMD_DENSE] * sqrt (n) entries are ignored
+ *         during the ordering, and placed last in the output order.  The
+ *         default value of Control [AMD_DENSE] is 10.  If negative, no
+ *         rows/columns are treated as "dense".  Rows/columns with 16 or
+ *         fewer off-diagonal entries are never considered "dense".
+ *
+ *     Control [AMD_AGGRESSIVE]: controls whether or not to use aggressive
+ *         absorption, in which a prior element is absorbed into the current
+ *         element if is a subset of the current element, even if it is not
+ *         adjacent to the current pivot element (refer to Amestoy, Davis,
+ *         & Duff, 1996, for more details).  The default value is nonzero,
+ *         which means to perform aggressive absorption.  This nearly always
+ *         leads to a better ordering (because the approximate degrees are
+ *         more accurate) and a lower execution time.  There are cases where
+ *         it can lead to a slightly worse ordering, however.  To turn it off,
+ *         set Control [AMD_AGGRESSIVE] to 0.
+ *
+ *     Control [2..4] are not used in the current version, but may be used in
+ *         future versions.
+ *
+ * The Info array provides statistics about the ordering on output.  If it is
+ * not present, the statistics are not returned.  This is not an error
+ * condition.
+ * 
+ *     Info [AMD_STATUS]:  the return value of AMD, either AMD_OK,
+ *         AMD_OUT_OF_MEMORY, or AMD_INVALID.
+ *
+ *     Info [AMD_N]: n, the size of the input matrix
+ *
+ *     Info [AMD_NZ]: the number of nonzeros in A, nz = Ap [n]
+ *
+ *     Info [AMD_SYMMETRY]:  the symmetry of the matrix A.  It is the number
+ *         of "matched" off-diagonal entries divided by the total number of
+ *         off-diagonal entries.  An entry A(i,j) is matched if A(j,i) is also
+ *         an entry, for any pair (i,j) for which i != j.  In MATLAB notation,
+ *             S = spones (A) ;
+ *             B = tril (S, -1) + triu (S, 1) ;
+ *             symmetry = nnz (B & B') / nnz (B) ;
+ *
+ *     Info [AMD_NZDIAG]: the number of entries on the diagonal of A.
+ *
+ *     Info [AMD_NZ_A_PLUS_AT]:  the number of nonzeros in A+A', excluding the
+ *         diagonal.  If A is perfectly symmetric (Info [AMD_SYMMETRY] = 1)
+ *         with a fully nonzero diagonal, then Info [AMD_NZ_A_PLUS_AT] = nz-n
+ *         (the smallest possible value).  If A is perfectly unsymmetric
+ *         (Info [AMD_SYMMETRY] = 0, for an upper triangular matrix, for
+ *         example) with no diagonal, then Info [AMD_NZ_A_PLUS_AT] = 2*nz
+ *         (the largest possible value).
+ *
+ *     Info [AMD_NDENSE]: the number of "dense" rows/columns of A+A' that were
+ *         removed from A prior to ordering.  These are placed last in the
+ *         output order P.
+ *
+ *     Info [AMD_MEMORY]: the amount of memory used by AMD, in bytes.  In the
+ *         current version, this is 1.2 * Info  [AMD_NZ_A_PLUS_AT] + 9*n
+ *         times the size of an integer.  This is at most 2.4nz + 9n.  This
+ *         excludes the size of the input arguments Ai, Ap, and P, which have
+ *         a total size of nz + 2*n + 1 integers.
+ *
+ *     Info [AMD_NCMPA]: the number of garbage collections performed.
+ *
+ *     Info [AMD_LNZ]: the number of nonzeros in L (excluding the diagonal).
+ *         This is a slight upper bound because mass elimination is combined
+ *         with the approximate degree update.  It is a rough upper bound if
+ *         there are many "dense" rows/columns.  The rest of the statistics,
+ *         below, are also slight or rough upper bounds, for the same reasons.
+ *         The post-ordering of the assembly tree might also not exactly
+ *         correspond to a true elimination tree postordering.
+ *
+ *     Info [AMD_NDIV]: the number of divide operations for a subsequent LDL'
+ *         or LU factorization of the permuted matrix A (P,P).
+ *
+ *     Info [AMD_NMULTSUBS_LDL]:  the number of multiply-subtract pairs for a
+ *         subsequent LDL' factorization of A (P,P).
+ *
+ *     Info [AMD_NMULTSUBS_LU]:  the number of multiply-subtract pairs for a
+ *         subsequent LU factorization of A (P,P), assuming that no numerical
+ *         pivoting is required.
+ *
+ *     Info [AMD_DMAX]:  the maximum number of nonzeros in any column of L,
+ *         including the diagonal.
+ *
+ *     Info [14..19] are not used in the current version, but may be used in
+ *         future versions.
+ */    
+
+/* ------------------------------------------------------------------------- */
+/* AMD preprocess */
+/* ------------------------------------------------------------------------- */
+
+/* amd_preprocess: sorts, removes duplicate entries, and transposes the
+ * nonzero pattern of a column-form matrix A, to obtain the matrix R.
+ *
+ * Alternatively, you can consider this routine as constructing a row-form
+ * matrix from a column-form matrix.  Duplicate entries are allowed in A (and
+ * removed in R). The columns of R are sorted.  Checks its input A for errors.
+ *
+ * On input, A can have unsorted columns, and can have duplicate entries.
+ * Ap [0] must still be zero, and Ap must be monotonically nondecreasing.
+ * Row indices must be in the range 0 to n-1.
+ *
+ * On output, if this routine returns AMD_OK, then the matrix R is a valid
+ * input matrix for AMD_order.  It has sorted columns, with no duplicate
+ * entries in each column.  Since AMD_order operates on the matrix A+A', it
+ * can just as easily use A or A', so the transpose has no significant effect
+ * (except for minor tie-breaking, which can lead to a minor effect in the
+ * quality of the ordering).  As an example, compare the output of amd_demo.c
+ * and amd_demo2.c.
+ *
+ * This routine transposes A to get R because that's the simplest way to
+ * sort and remove duplicate entries from a matrix.
+ *
+ * Allocates 2*n integer work arrays, and free's them when done.
+ *
+ * If you wish to call amd_order, but do not know if your matrix has unsorted
+ * columns or duplicate entries, then you can use the following code, which is
+ * fairly efficient.  amd_order will not allocate any internal matrix until
+ * it checks that the input matrix is valid, so the method below is memory-
+ * efficient as well.  This code snippet assumes that Rp and Ri are already
+ * allocated, and are the same size as Ap and Ai respectively.
+
+    result = amd_order (n, p, Ap, Ai, Control, Info) ;
+    if (result == AMD_INVALID)
+    {
+       if (amd_preprocess (n, Ap, Ai, Rp, Ri) == AMD_OK)
+       {
+           result = amd_order (n, p, Rp, Ri, Control, Info) ;
+       }
+    }
+
+ * amd_preprocess will still return AMD_INVALID if any row index in Ai is out
+ * of range or if the Ap array is invalid.  These errors are not corrected by
+ * amd_preprocess since they represent a more serious error that should be
+ * flagged with the AMD_INVALID error code.
+ */ 
+
+int amd_preprocess
+(
+    int n,
+    const int Ap [ ],
+    const int Ai [ ],
+    int Rp [ ],
+    int Ri [ ]
+) ;
+
+long amd_l_preprocess
+(
+    long n,
+    const long Ap [ ],
+    const long Ai [ ],
+    long Rp [ ],
+    long Ri [ ]
+) ;
+
+/* Input arguments (not modified):
+ *
+ *     n: the matrix A is n-by-n.
+ *     Ap: an int/long array of size n+1, containing the column pointers of A.
+ *     Ai: an int/long array of size nz, containing the row indices of A,
+ *         where nz = Ap [n].
+ *     The nonzero pattern of column j of A is in Ai [Ap [j] ... Ap [j+1]-1].
+ *     Ap [0] must be zero, and Ap [j] <= Ap [j+1] must hold for all j in the
+ *     range 0 to n-1.  Row indices in Ai must be in the range 0 to n-1.
+ *     The row indices in any one column need not be sorted, and duplicates
+ *     may exist.
+ *
+ * Output arguments (not defined on input):
+ *
+ *     Rp: an int/long array of size n+1, containing the column pointers of R.
+ *     Ri: an int/long array of size rnz, containing the row indices of R,
+ *         where rnz = Rp [n].  Note that Rp [n] will be less than Ap [n] if
+ *         duplicates appear in A.  In general, Rp [n] <= Ap [n].
+ *      The data structure for R is the same as A, except that each column of
+ *      R contains sorted row indices, and no duplicates appear in any column.
+ *
+ * amd_preprocess returns:
+ *
+ *     AMD_OK if the matrix A is valid and sufficient memory can be allocated
+ *         to perform the preprocessing.
+ *
+ *     AMD_OUT_OF_MEMORY if not enough memory can be allocated.
+ *
+ *     AMD_INVALID if the input arguments n, Ap, Ai are invalid, or if Rp or
+ *         Ri are NULL.
+ */
+
+/* ------------------------------------------------------------------------- */
+/* 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 */
+#define AMD_INVALID -2         /* input arguments are not valid */
+
+#endif
diff --git a/deal.II/contrib/umfpack/AMD/MATLAB/Contents.m b/deal.II/contrib/umfpack/AMD/MATLAB/Contents.m
new file mode 100644 (file)
index 0000000..8200578
--- /dev/null
@@ -0,0 +1,13 @@
+%Contents of the AMD sparse matrix ordering package:
+%
+% amd              p = amd (A), the approximate minimum degree ordering of A
+% amd_demo         a demo of amd, using the can_24 matrix
+% amd_make         to comple amd for use in MATLAB
+% can_24.mat       a sample sparse matrix from the Harwell/Boeing collection
+%
+% See also:  amd, colamd, symamd, colmmd, symmmd, umfpack
+%
+% AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,
+% Patrick R. Amestoy, and Iain S. Duff.  All Rights Reserved.
+
+help Contents
diff --git a/deal.II/contrib/umfpack/AMD/MATLAB/GNUmakefile b/deal.II/contrib/umfpack/AMD/MATLAB/GNUmakefile
new file mode 100644 (file)
index 0000000..ad97a78
--- /dev/null
@@ -0,0 +1,30 @@
+#------------------------------------------------------------------------------
+# GNUmakefile for the AMD MATLAB mexFunction
+#------------------------------------------------------------------------------
+
+all: amd
+
+include ../Make/Make.include
+
+MX = $(MEX) -I../Include
+
+AMD = amd_aat amd_1 amd_2 amd_dump amd_postorder amd_post_tree amd_defaults \
+       amd_order amd_control amd_info amd_valid
+
+INC = ../Include/amd.h ../Source/amd_internal.h
+
+MEXAMD = $(addsuffix .o, $(subst amd_,amd_m_,$(AMD)))
+
+amd_m_%.o: ../Source/amd_%.c $(INC)
+       $(MX) -DDINT -c $<
+       - $(MV) amd_$*.o $@
+
+amd: amd_mex.c $(MEXAMD) $(INC)
+       $(MX) -output amd amd_mex.c $(MEXAMD)
+
+#------------------------------------------------------------------------------
+# Remove all but the files in the original distribution
+#------------------------------------------------------------------------------
+
+purge: clean
+       - $(RM) amd.mex* amd.dll
diff --git a/deal.II/contrib/umfpack/AMD/MATLAB/Makefile b/deal.II/contrib/umfpack/AMD/MATLAB/Makefile
new file mode 100644 (file)
index 0000000..d3c4f8c
--- /dev/null
@@ -0,0 +1,50 @@
+#------------------------------------------------------------------------------
+# compile the AMD mexFunction for MATLAB (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.  It was created
+# automatically, via make -n using the GNUmakefile.  That way, I don't have
+# maintain two Makefiles.
+
+all: amd
+
+include ../Make/Make.include
+
+MX = $(MEX) -I../Include
+
+amd:
+       $(MX) -DDINT -c ../Source/amd_aat.c
+       $(MV) amd_aat.o amd_m_aat.o
+       $(MX) -DDINT -c ../Source/amd_1.c
+       $(MV) amd_1.o amd_m_1.o
+       $(MX) -DDINT -c ../Source/amd_2.c
+       $(MV) amd_2.o amd_m_2.o
+       $(MX) -DDINT -c ../Source/amd_dump.c
+       $(MV) amd_dump.o amd_m_dump.o
+       $(MX) -DDINT -c ../Source/amd_postorder.c
+       $(MV) amd_postorder.o amd_m_postorder.o
+       $(MX) -DDINT -c ../Source/amd_post_tree.c
+       $(MV) amd_post_tree.o amd_m_post_tree.o
+       $(MX) -DDINT -c ../Source/amd_defaults.c
+       $(MV) amd_defaults.o amd_m_defaults.o
+       $(MX) -DDINT -c ../Source/amd_order.c
+       $(MV) amd_order.o amd_m_order.o
+       $(MX) -DDINT -c ../Source/amd_control.c
+       $(MV) amd_control.o amd_m_control.o
+       $(MX) -DDINT -c ../Source/amd_info.c
+       $(MV) amd_info.o amd_m_info.o
+       $(MX) -DDINT -c ../Source/amd_valid.c
+       $(MV) amd_valid.o amd_m_valid.o
+       $(MX) -output amd amd_mex.c amd_m_aat.o \
+           amd_m_1.o amd_m_2.o amd_m_dump.o amd_m_postorder.o \
+           amd_m_post_tree.o amd_m_defaults.o amd_m_order.o amd_m_control.o \
+           amd_m_info.o amd_m_valid.o
+
+#------------------------------------------------------------------------------
+# Remove all but the files in the original distribution
+#------------------------------------------------------------------------------
+
+purge: clean
+       - $(RM) amd.mex* amd.dll
diff --git a/deal.II/contrib/umfpack/AMD/MATLAB/amd.m b/deal.II/contrib/umfpack/AMD/MATLAB/amd.m
new file mode 100644 (file)
index 0000000..610ce02
--- /dev/null
@@ -0,0 +1,74 @@
+function [p, Info] = amd (A, Control)
+%AMD Approximate minimum degree permutation.
+%    P = AMD (S) returns the approximate minimum degree permutation vector for
+%    the sparse matrix C = S+S'.  The Cholesky factorization of C (P,P), or
+%    S (P,P), tends to be sparser than that of C or S.  AMD tends to be faster
+%    than SYMMMD and SYMAMD, and tends to return better orderings than SYMMMD.
+%    S must be square. If S is full, amd (S) is equivalent to amd (sparse (S)).
+%
+%    Usage:  P = amd (S) ;                   % finds the ordering
+%            [P, Info] = amd (S, Control) ;  % optional parameters & statistics
+%            Control = amd ;                 % returns default parameters
+%            amd ;                           % prints default parameters.
+%
+%       Control (1); If S is n-by-n, then rows/columns with more than
+%           max (16, (Control (1))* sqrt(n)) entries in S+S' are considered
+%           "dense", and ignored during ordering.  They are placed last in the
+%           output permutation.  The default is 10.0 if Control is not present.
+%       Control (2): If nonzero, then aggressive absorption is performed.
+%           This is the default if Control is not present.
+%       Control (3): If nonzero, print statistics about the ordering.
+%
+%       Info (1): status (0: ok, -1: out of memory, -2: matrix invalid)
+%       Info (2): n = size (A,1)
+%       Info (3): nnz (A)
+%       Info (4): the symmetry of the matrix S (0.0 means purely unsymmetric,
+%           1.0 means purely symmetric).  Computed as:
+%           B = tril (S, -1) + triu (S, 1) ; symmetry = nnz (B & B') / nnz (B);
+%       Info (5): nnz (diag (S))
+%       Info (6): nnz in S+S', excluding the diagonal (= nnz (B+B'))
+%       Info (7): number "dense" rows/columns in S+S'
+%       Info (8): the amount of memory used by AMD, in bytes
+%       Info (9): the number of memory compactions performed by AMD
+%
+%    The following statistics are slight upper bounds because of the
+%    approximate degree in AMD.  The bounds are looser if "dense" rows/columns
+%    are ignored during ordering (Info (7) > 0).  The statistics are for a
+%    subsequent factorization of the matrix C (P,P).  The LU factorization
+%    statistics assume no pivoting.
+%
+%       Info (10): the number of nonzeros in L, excluding the diagonal
+%       Info (11): the number of divide operations for LL', LDL', or LU
+%       Info (12): the number of multiply-subtract pairs for LL' or LDL'
+%       Info (13): the number of multiply-subtract pairs for LU
+%       Info (14): the max # of nonzeros in any column of L (incl. diagonal)
+%       Info (15:20): unused, reserved for future use
+%
+%    An assembly tree post-ordering is performed, which is typically the same
+%    as an elimination tree post-ordering.  It is not always identical because
+%    of the approximate degree update used, and because "dense" rows/columns
+%    do not take part in the post-order.  It well-suited for a subsequent
+%    "chol", however.  If you require a precise elimination tree post-ordering,
+%    then do:
+%
+%       P = amd (S) ;
+%       C = spones (S) + spones (S') ;  % skip this if S already symmetric
+%       [ignore, Q] = sparsfun ('symetree', C (P,P)) ;
+%       P = P (Q) ;
+%
+% --------------------------------------------------------------------------
+% AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,
+% Patrick R. Amestoy, and Iain S. Duff.  See ../README for License.
+% email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.
+% web: http://www.cise.ufl.edu/research/sparse/amd
+% --------------------------------------------------------------------------
+%
+%    Acknowledgements: This work was supported by the National Science
+%       Foundation, under grants ASC-9111263, DMS-9223088, and CCR-0203270.
+%
+%    See also COLMMD, COLAMD, COLPERM, SYMAMD, SYMMMD, SYMRCM.
+
+more on
+help amd
+more off
+error ('amd mexFunction not found!  Type "amd_make" in MATLAB to compile amd');
diff --git a/deal.II/contrib/umfpack/AMD/MATLAB/amd_demo.m b/deal.II/contrib/umfpack/AMD/MATLAB/amd_demo.m
new file mode 100644 (file)
index 0000000..a2d6c72
--- /dev/null
@@ -0,0 +1,96 @@
+function amd_demo
+% AMD DEMO
+%
+% A demo of AMD for MATLAB.
+%
+% --------------------------------------------------------------------------
+% AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,
+% Patrick R. Amestoy, and Iain S. Duff.  See ../README for License.
+% email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.
+% web: http://www.cise.ufl.edu/research/sparse/amd
+% --------------------------------------------------------------------------
+%
+% See also: amd, amd_make
+
+% This orders the same matrix as the ANSI C demo, amd_demo.c.  It includes an
+% additional analysis of the matrix via MATLAB's symbfact routine.
+
+% First, print the help information for AMD
+help amd
+
+% Get the Harwell/Boeing can_24 matrix.  This is an example matrix from the
+% MATLAB-accessible UF sparse matrix collection, and can be loaded into
+% MATLAB with the statment "Problem = UFget ('HB/can_24')", after obtaining
+% the UFget function and its supporting routines at
+% http://www.cise.ufl.edu/sparse/mat .
+
+load can_24
+A = Problem.A ;
+n = size (A,1) ;
+
+figure (1)
+clf
+hold off
+subplot (2,2,1) ;
+spy (A)
+% remove the "_" from the name before printing it in the plot title
+title (sprintf ('%s', strrep (Problem.name, '_', '-'))) ;
+fprintf ('Matrix name:  %s\n', Problem.name) ;
+fprintf ('Matrix title: %s\n', Problem.title) ;
+
+% print the details during AMD ordering and SYMBFACT
+spparms ('spumoni', 1) ;
+
+% order the matrix.  Note that the Info argument is optional.
+fprintf ('\nIf the next step fails, then you have\n') ;
+fprintf ('not yet compiled the AMD mexFunction.\n') ;
+[p, Info] = amd (A) ;
+
+% order again, but this time print some statistics
+[p, Info] = amd (A, [10 1 1]) ;
+
+fprintf ('Permutation vector:\n') ;
+fprintf (' %2d', p) ;
+fprintf ('\n\n') ;
+
+subplot (2,2,2) ;
+spy (A (p,p))
+title ('Permuted matrix') ;
+
+% The amd_demo.c program stops here.
+
+fprintf ('Analyze A(p,p) with MATLAB''s symbfact routine:\n') ;
+[cn, height, parent, post, R] = symbfact (A (p,p)) ;
+
+subplot (2,2,3) ;
+spy (R') ; 
+title ('Cholesky factor, L') ;
+
+subplot (2,2,4) ;
+treeplot (parent) ;
+title ('elimination tree') ;
+
+% results from symbfact
+lnz = sum (cn) ;                % number of nonzeros in L, incl. diagonal
+cn = cn - 1 ;                   % get the count of off-diagonal entries
+fl = n + sum (cn.^2 + 2*cn) ;   % flop count for chol (A (p,p)
+fprintf ('number of nonzeros in L (including diagonal):      %d\n', lnz) ;
+fprintf ('floating point operation count for chol (A (p,p)): %d\n', fl) ;
+
+% approximations from amd:
+lnz2 = n + Info (10) ;
+fl2 = n + Info (11) + 2 * Info (12) ;
+fprintf ('\nResults from AMD''s approximate analysis:\n') ;
+fprintf ('number of nonzeros in L (including diagonal):      %d\n', lnz2) ;
+fprintf ('floating point operation count for chol (A (p,p)): %d\n\n', fl2) ;
+
+if (lnz2 ~= lnz | fl ~= fl2)
+    fprintf ('Note that the nonzero and flop counts from AMD are slight\n') ;
+    fprintf ('upper bounds.  This is due to the approximate minimum degree\n');
+    fprintf ('method used, in conjunction with "mass elimination".\n') ;
+    fprintf ('See the discussion about mass elimination in amd.h and\n') ;
+    fprintf ('amd_2.c for more details.\n') ;
+end
+
+% turn off diagnostic output in MATLAB's sparse matrix routines
+spparms ('spumoni', 0) ;
diff --git a/deal.II/contrib/umfpack/AMD/MATLAB/amd_demo.m.out b/deal.II/contrib/umfpack/AMD/MATLAB/amd_demo.m.out
new file mode 100644 (file)
index 0000000..b77732f
--- /dev/null
@@ -0,0 +1,136 @@
+>> amd_demo
+
+ AMD Approximate minimum degree permutation.
+     P = AMD (S) returns the approximate minimum degree permutation vector for
+     the sparse matrix C = S+S'.  The Cholesky factorization of C (P,P), or
+     S (P,P), tends to be sparser than that of C or S.  AMD tends to be faster
+     than SYMMMD and SYMAMD, and tends to return better orderings than SYMMMD.
+     S must be square. If S is full, amd (S) is equivalent to amd (sparse (S)).
+     Usage:  P = amd (S) ;                   % finds the ordering
+             [P, Info] = amd (S, Control) ;  % optional parameters & statistics
+             Control = amd ;                 % returns default parameters
+             amd ;                           % prints default parameters.
+        Control (1); If S is n-by-n, then rows/columns with more than
+            max (16, (Control (1))* sqrt(n)) entries in S+S' are considered
+            "dense", and ignored during ordering.  They are placed last in the
+            output permutation.  The default is 10.0 if Control is not present.
+        Control (2): If nonzero, then aggressive absorption is performed.
+            This is the default if Control is not present.
+        Control (3): If nonzero, print statistics about the ordering.
+        Info (1): status (0: ok, -1: out of memory, -2: matrix invalid)
+        Info (2): n = size (A,1)
+        Info (3): nnz (A)
+        Info (4): the symmetry of the matrix S (0.0 means purely unsymmetric,
+            1.0 means purely symmetric).  Computed as:
+            B = tril (S, -1) + triu (S, 1) ; symmetry = nnz (B & B') / nnz (B);
+        Info (5): nnz (diag (S))
+        Info (6): nnz in S+S', excluding the diagonal (= nnz (B+B'))
+        Info (7): number "dense" rows/columns in S+S'
+        Info (8): the amount of memory used by AMD, in bytes
+        Info (9): the number of memory compactions performed by AMD
+     The following statistics are slight upper bounds because of the
+     approximate degree in AMD.  The bounds are looser if "dense" rows/columns
+     are ignored during ordering (Info (7) > 0).  The statistics are for a
+     subsequent factorization of the matrix C (P,P).  The LU factorization
+     statistics assume no pivoting.
+        Info (10): the number of nonzeros in L, excluding the diagonal
+        Info (11): the number of divide operations for LL', LDL', or LU
+        Info (12): the number of multiply-subtract pairs for LL' or LDL'
+        Info (13): the number of multiply-subtract pairs for LU
+        Info (14): the max # of nonzeros in any column of L (incl. diagonal)
+        Info (15:20): unused, reserved for future use
+     An assembly tree post-ordering is performed, which is typically the same
+     as an elimination tree post-ordering.  It is not always identical because
+     of the approximate degree update used, and because "dense" rows/columns
+     do not take part in the post-order.  It well-suited for a subsequent
+     "chol", however.  If you require a precise elimination tree post-ordering,
+     then do:
+        P = amd (S) ;
+        C = spones (S) + spones (S') ;  % skip this if S already symmetric
+        [ignore, Q] = sparsfun ('symetree', C (P,P)) ;
+        P = P (Q) ;
+  --------------------------------------------------------------------------
+  AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,
+  Patrick R. Amestoy, and Iain S. Duff.  See ../README for License.
+  email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.
+  web: http://www.cise.ufl.edu/research/sparse/amd
+  --------------------------------------------------------------------------
+     Acknowledgements: This work was supported by the National Science
+        Foundation, under grants ASC-9111263, DMS-9223088, and CCR-0203270.
+     See also COLMMD, COLAMD, COLPERM, SYMAMD, SYMMMD, SYMRCM.
+
+Matrix name:  HB/can_24
+Matrix title: 1SYMMETRIC PATTERN FROM CANNES,LUCIEN MARRO,JUNE 1981.                  
+
+If the next step fails, then you have
+not yet compiled the AMD mexFunction.
+
+amd:  approximate minimum degree ordering, parameters:
+    dense row parameter: 10
+    (rows with more than max (10 * sqrt (n), 16) entries are
+    considered "dense", and placed last in output permutation)
+    aggressive absorption:  yes
+
+    input matrix A is 24-by-24
+    input matrix A has 160 nonzero entries
+
+amd:  approximate minimum degree ordering, results:
+    status: OK
+    n, dimension of A:                                  24
+    nz, number of nonzeros in A:                        160
+    symmetry of A:                                      1.0000
+    number of nonzeros on diagonal:                     24
+    nonzeros in pattern of A+A' (excl. diagonal):       136
+    # dense rows/columns of A+A':                       0
+    memory used, in bytes:                              1516
+    # of memory compactions:                            0
+
+    The following approximate statistics are for a subsequent
+    factorization of A(P,P) + A(P,P)'.  They are slight upper
+    bounds if there are no dense rows/columns in A+A', and become
+    looser if dense rows/columns exist.
+
+    nonzeros in L (excluding diagonal):                 97
+    nonzeros in L (including diagonal):                 121
+    # divide operations for LDL' or LU:                 97
+    # multiply-subtract operations for LDL':            275
+    # multiply-subtract operations for LU:              453
+    max nz. in any column of L (incl. diagonal):        8
+
+    chol flop count for real A, sqrt counted as 1 flop: 671
+    LDL' flop count for real A:                         647
+    LDL' flop count for complex A:                      3073
+    LU flop count for real A (with no pivoting):        1003
+    LU flop count for complex A (with no pivoting):     4497
+
+Permutation vector:
+ 23 21 11 24 13  6 17  9 15  5 16  8  2 10 14 18  1  3  4  7 12 19 22 20
+
+Analyze A(p,p) with MATLAB's symbfact routine:
+predicted nonzeros:    120
+predicted flops:       656
+predicted height:      16
+predicted front size:  7
+number of nonzeros in L (including diagonal):      120
+floating point operation count for chol (A (p,p)): 656
+
+Results from AMD's approximate analysis:
+number of nonzeros in L (including diagonal):      121
+floating point operation count for chol (A (p,p)): 671
+
+Note that the nonzero and flop counts from AMD are slight
+upper bounds.  This is due to the approximate minimum degree
+method used, in conjunction with "mass elimination".
+See the discussion about mass elimination in amd.h and
+amd_2.c for more details.
+>> diary off
diff --git a/deal.II/contrib/umfpack/AMD/MATLAB/amd_make.m b/deal.II/contrib/umfpack/AMD/MATLAB/amd_make.m
new file mode 100644 (file)
index 0000000..4668c55
--- /dev/null
@@ -0,0 +1,32 @@
+function amd_make
+% AMD_MAKE:  compiles the AMD mexFunction for MATLAB
+%
+% --------------------------------------------------------------------------
+% AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,
+% Patrick R. Amestoy, and Iain S. Duff.  See ../README for License.
+% email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.
+% web: http://www.cise.ufl.edu/research/sparse/amd
+% --------------------------------------------------------------------------
+%
+% See also: amd, amd_demo
+
+help amd_make
+fprintf ('Compiling the AMD mexFunction:\n') ;
+cmd = sprintf ('mex -inline -O -output amd -I..%sInclude amd_mex.c', filesep) ;
+files = {'amd_order', 'amd_dump', 'amd_postorder', 'amd_post_tree', ...
+    'amd_aat', 'amd_2', 'amd_1', 'amd_defaults', 'amd_control', 'amd_info', ...
+    'amd_valid' } ;
+for i = 1 : length (files)
+    cmd = sprintf ('%s ..%sSource%s%s.c', cmd, filesep, filesep, files {i}) ;
+end
+fprintf ('%s\n', cmd) ;
+try
+    eval (cmd) ;
+catch
+    fprintf ('Compilation not successful.\n') ;
+end
+
+input ('\nHit enter to run the AMD demo\n') ;
+more on
+amd_demo
+more off
diff --git a/deal.II/contrib/umfpack/AMD/MATLAB/amd_mex.c b/deal.II/contrib/umfpack/AMD/MATLAB/amd_mex.c
new file mode 100644 (file)
index 0000000..0b36690
--- /dev/null
@@ -0,0 +1,189 @@
+/* ========================================================================= */
+/* === AMD mexFunction ===================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,  */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README for License.         */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.           */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Usage:
+ *     p = amd (A)
+ *     p = amd (A, Control)
+ *     [p, Info] = amd (A)
+ *     [p, Info] = amd (A, Control)
+ *     Control = amd ;     % return the default Control settings for AMD
+ *     amd ;               % print the default Control settings for AMD
+ *
+ * Given a square matrix A, compute a permutation P suitable for a Cholesky
+ * factorization of the matrix B (P,P), where B = spones (A) + spones (A').
+ * The method used is the approximate minimum degree ordering method.  See
+ * amd.m and amd.h for more information.
+ */
+
+#include "amd.h"
+#include "mex.h"
+#include "matrix.h"
+
+void mexFunction
+(
+    int        nlhs,
+    mxArray *plhs[],
+    int        nrhs,
+    const mxArray *prhs[]
+)
+{
+    int i, m, n, *Ap, *Ai, *P, nc, result, spumoni, full ;
+    double *Pout, *InfoOut, Control [AMD_CONTROL], Info [AMD_INFO], *ControlIn;
+    mxArray *A, *string, *parameter ;
+
+    /* --------------------------------------------------------------------- */
+    /* get control parameters */
+    /* --------------------------------------------------------------------- */
+
+    spumoni = 0 ;
+    if (nrhs == 0)
+    {
+       /* get the default control parameters, and return */
+       plhs [0] = mxCreateDoubleMatrix (AMD_CONTROL, 1, mxREAL) ;
+       amd_defaults (mxGetPr (plhs [0])) ;
+       if (nlhs == 0)
+       {
+           amd_control (mxGetPr (plhs [0])) ;
+       }
+       return ;
+    }
+
+    amd_defaults (Control) ;
+    if (nrhs > 1)
+    {
+       ControlIn = mxGetPr (prhs [1]) ;
+       nc = mxGetM (prhs [1]) * mxGetN (prhs [1]) ;
+       Control [AMD_DENSE]
+           = (nc > 0) ? ControlIn [AMD_DENSE] : AMD_DEFAULT_DENSE ;
+       Control [AMD_AGGRESSIVE]
+           = (nc > 1) ? ControlIn [AMD_AGGRESSIVE] : AMD_DEFAULT_AGGRESSIVE ;
+       spumoni = (nc > 2) ? (ControlIn [2] != 0) : 0 ;
+    }
+
+    if (spumoni > 0)
+    {
+       amd_control (Control) ;
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* get inputs */
+    /* --------------------------------------------------------------------- */
+
+    if (nlhs > 2 || nrhs > 2)
+    {
+       mexErrMsgTxt ("Usage: p = amd (A)\nor [p, Info] = amd (A, Control)") ;
+    }
+
+    A = (mxArray *) prhs [0] ;
+    n = mxGetN (A) ;
+    m = mxGetM (A) ;
+    if (spumoni > 0)
+    {
+       mexPrintf ("    input matrix A is %d-by-%d\n", m, n) ;
+    }
+    if (mxGetNumberOfDimensions (A) != 2)
+    {
+       mexErrMsgTxt ("amd: A must be 2-dimensional") ;
+    }
+    if (m != n)
+    {
+       mexErrMsgTxt ("amd: A must be square") ;
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* allocate workspace for output permutation */
+    /* --------------------------------------------------------------------- */
+
+    P = mxMalloc ((n+1) * sizeof (int)) ;
+
+    /* --------------------------------------------------------------------- */
+    /* if A is full, convert to a sparse matrix */
+    /* --------------------------------------------------------------------- */
+
+    full = !mxIsSparse (A) ;
+    if (full)
+    {
+       if (spumoni > 0)
+       {
+           mexPrintf (
+           "    input matrix A is full (sparse copy of A will be created)\n");
+       }
+       mexCallMATLAB (1, &A, 1, (mxArray **) prhs, "sparse") ;
+    }
+    Ap = mxGetJc (A) ;
+    Ai = mxGetIr (A) ;
+    if (spumoni > 0)
+    {
+       mexPrintf ("    input matrix A has %d nonzero entries\n", Ap [n]) ;
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* order the matrix */
+    /* --------------------------------------------------------------------- */
+
+    result = amd_order (n, Ap, Ai, P, Control, Info) ;
+
+    /* --------------------------------------------------------------------- */
+    /* if A is full, free the sparse copy of A */
+    /* --------------------------------------------------------------------- */
+
+    if (full)
+    {
+       mxDestroyArray (A) ;
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* print results (including return value) */
+    /* --------------------------------------------------------------------- */
+
+    if (spumoni > 0)
+    {
+       amd_info (Info) ;
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* check error conditions */
+    /* --------------------------------------------------------------------- */
+
+    if (result == AMD_OUT_OF_MEMORY)
+    {
+       mexErrMsgTxt ("amd: out of memory") ;
+    }
+    else if (result == AMD_INVALID)
+    {
+       mexErrMsgTxt ("amd: input matrix A is corrupted") ;
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* copy the outputs to MATLAB */
+    /* --------------------------------------------------------------------- */
+
+    /* output permutation, P */
+    plhs [0] = mxCreateDoubleMatrix (1, n, mxREAL) ;
+    Pout = mxGetPr (plhs [0])  ;
+    for (i = 0 ; i < n ; i++)
+    {
+       Pout [i] = P [i] + 1 ;      /* change to 1-based indexing for MATLAB */
+    }
+    mxFree (P) ;
+
+    /* Info */
+    if (nlhs > 1)
+    {
+       plhs [1] = mxCreateDoubleMatrix (AMD_INFO, 1, mxREAL) ;
+       InfoOut = mxGetPr (plhs [1]) ;
+       for (i = 0 ; i < AMD_INFO ; i++)
+       {
+           InfoOut [i] = Info [i] ;
+       }
+    }
+}
diff --git a/deal.II/contrib/umfpack/AMD/MATLAB/can_24.mat b/deal.II/contrib/umfpack/AMD/MATLAB/can_24.mat
new file mode 100644 (file)
index 0000000..a346d0d
Binary files /dev/null and b/deal.II/contrib/umfpack/AMD/MATLAB/can_24.mat differ
diff --git a/deal.II/contrib/umfpack/AMD/README b/deal.II/contrib/umfpack/AMD/README
new file mode 100644 (file)
index 0000000..e47f18e
--- /dev/null
@@ -0,0 +1,202 @@
+AMD version 1.1:  a set of routines for permuting sparse matrices prior to
+    factorization.  Includes a version in C, a version in Fortran, and a MATLAB
+    mexFunction.
+
+Quick start (Unix, or Windows with Cygwin):
+
+    To compile, test, and install AMD, you may wish to first configure the
+    installation by editting the AMD/Make/Make.include 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 AMD/Make/Make.include, 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.
+    This works on any system supported by MATLAB.
+
+-------------------------------------------------------------------------------
+
+AMD Version 1.1 (Jan. 21, 2004),  Copyright (c) 2004 by Timothy A.
+Davis, Patrick R. Amestoy, and Iain S. Duff.  All Rights Reserved.
+
+AMD License:
+
+    Your use or distribution of AMD or any modified version of
+    AMD implies that you agree to this License.
+
+    THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
+    EXPRESSED OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+
+    Permission is hereby granted to use or copy this program, provided
+    that the Copyright, this License, and the Availability of the original
+    version is retained on all copies.  User documentation of any code that
+    uses AMD or any modified version of AMD code must cite the
+    Copyright, this License, the Availability note, and "Used by permission."
+    Permission to modify the code and to distribute modified code is granted,
+    provided the Copyright, this License, and the Availability note are
+    retained, and a notice that the code was modified is included.  This
+    software was developed with support from the National Science Foundation,
+    and is provided to you free of charge.
+
+Availability:
+
+    http://www.cise.ufl.edu/research/sparse/amd
+
+-------------------------------------------------------------------------------
+
+This is the AMD Version 1.1 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@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 v1.0 distribution:
+-------------------------------------------------------------------------------
+
+    ---------------------------------------------------------------------------
+    Subdirectories of the AMD directory:
+    ---------------------------------------------------------------------------
+
+    Doc                documentation
+    Make       for compiling AMD
+    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     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)
+
+    ---------------------------------------------------------------------------
+    Make directory: for compiling AMD (Lib/libamd.a and Lib/libamdf77.a)
+    ---------------------------------------------------------------------------
+
+    Make.include               overall configurations.  Can use one of: 
+    Make.alpha                 Makefile additions for Compaq Alpha
+    Make.linux                 Makefile additions for Linux
+    Make.rs6000                        Makefile additions for RS 6000
+    Make.sgi                   Makefile additions for SGI
+    Make.solaris               Makefile additions for Solaris
+
+    ---------------------------------------------------------------------------
+    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                    non-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_internal.h             non-user-callable, include file for AMD
+    amd_mex.c                  non-user-callable, MATLAB mexFunction
+    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.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
+
+    ---------------------------------------------------------------------------
+    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_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 amd" listing of toolbox contents
+
+    amd.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/deal.II/contrib/umfpack/AMD/Source/Makefile b/deal.II/contrib/umfpack/AMD/Source/Makefile
new file mode 100644 (file)
index 0000000..a285ac5
--- /dev/null
@@ -0,0 +1,35 @@
+#-------------------------------------------------------------------------------
+# AMD Makefile for compiling on Unix systems (for GNU make only)
+#-------------------------------------------------------------------------------
+
+include ../../../../common/Make.global_options
+
+#-------------------------------------------------------------------------------
+# 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
+
+INC = ../Include/amd.h amd_internal.h
+
+#-------------------------------------------------------------------------------
+# object files for each version
+#-------------------------------------------------------------------------------
+
+AMDI = $(addprefix $D/lib/umfpack/, $(addsuffix .$(OBJEXT), $(subst amd_,amd_i_,$(AMD))))
+AMDL = $(addprefix $D/lib/umfpack/, $(addsuffix .$(OBJEXT), $(subst amd_,amd_l_,$(AMD))))
+
+#-------------------------------------------------------------------------------
+# compile each int and long routine (with no real/complex version)
+#-------------------------------------------------------------------------------
+
+$D/lib/umfpack/amd_i_%.$(OBJEXT): amd_%.c $(INC)
+       @echo =====umfpack==========optimized==$(MT)== $(<F)
+       $(CC) $(CFLAGS) -I../Include -DDINT -c $< -o $@
+
+$D/lib/umfpack/amd_l_%.$(OBJEXT): amd_%.c $(INC)
+       @echo =====umfpack==========optimized==$(MT)== $(<F)
+       $(CC) $(CFLAGS) -I../Include -DDLONG -c $< -o $@
+
+all: $(AMDI) $(AMDL)
diff --git a/deal.II/contrib/umfpack/AMD/Source/amd.f b/deal.II/contrib/umfpack/AMD/Source/amd.f
new file mode 100644 (file)
index 0000000..ccfe3e8
--- /dev/null
@@ -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/deal.II/contrib/umfpack/AMD/Source/amd_1.c b/deal.II/contrib/umfpack/AMD/Source/amd_1.c
new file mode 100644 (file)
index 0000000..4a3fdb0
--- /dev/null
@@ -0,0 +1,181 @@
+/* ========================================================================= */
+/* === AMD_1 =============================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,  */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README for License.         */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.           */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* AMD_1: Construct A+A' for a sparse matrix A and perform the AMD ordering.
+ *
+ * The n-by-n sparse matrix A can be unsymmetric.  It is stored in MATLAB-style
+ * compressed-column form, with sorted row indices in each column, and no
+ * duplicate entries.  Diagonal entries may be present, but they are ignored.
+ * Row indices of column j of A are stored in Ai [Ap [j] ... Ap [j+1]-1].
+ * Ap [0] must be zero, and nz = Ap [n] is the number of entries in A.  The
+ * size of the matrix, n, must be greater than or equal to zero.
+ *
+ * This routine must be preceded by a call to AMD_aat, which computes the
+ * number of entries in each row/column in A+A', excluding the diagonal.
+ * Len [j], on input, is the number of entries in row/column j of A+A'.  This
+ * routine constructs the matrix A+A' and then calls AMD_2.  No error checking
+ * is performed (this was done in AMD_aat).
+ */
+
+#include "amd_internal.h"
+
+GLOBAL void AMD_1
+(
+    Int n,             /* n > 0 */
+    const Int Ap [ ],  /* input of size n+1, not modified */
+    const Int Ai [ ],  /* input of size nz = Ap [n], not modified */
+    Int P [ ],         /* size n output permutation */
+    Int Pinv [ ],      /* size n output inverse permutation */
+    Int Len [ ],       /* size n input, undefined on output */
+    Int slen,          /* slen >= sum (Len [0..n-1]) + 7n,
+                        * ideally slen = 1.2 * sum (Len) + 8n */
+    Int S [ ],         /* size slen workspace */
+    double Control [ ],        /* input array of size AMD_CONTROL */
+    double Info [ ]    /* output array of size AMD_INFO */
+)
+{
+    Int i, j, k, p, pfree, iwlen, pj, p1, p2, pj2, *Iw, *Pe, *Nv, *Head,
+       *Elen, *Degree, *s, *W, *Sp, *Tp ;
+
+    /* --------------------------------------------------------------------- */
+    /* construct the matrix for AMD_2 */
+    /* --------------------------------------------------------------------- */
+
+    ASSERT (n > 0) ;
+
+    iwlen = slen - 6*n ;
+    s = S ;
+    Pe = s ;       s += n ;
+    Nv = s ;       s += n ;
+    Head = s ;     s += n ;
+    Elen = s ;     s += n ;
+    Degree = s ;    s += n ;
+    W = s ;        s += n ;
+    Iw = s ;       s += iwlen ;
+
+    ASSERT (AMD_valid (n, n, Ap, Ai)) ;
+
+    /* construct the pointers for A+A' */
+    Sp = Nv ;                  /* use Nv and W as workspace for Sp and Tp [ */
+    Tp = W ;
+    pfree = 0 ;
+    for (j = 0 ; j < n ; j++)
+    {
+       Pe [j] = pfree ;
+       Sp [j] = pfree ;
+       pfree += Len [j] ;
+    }
+
+    /* Note that this restriction on iwlen is slightly more restrictive than
+     * what is strictly required in AMD_2.  AMD_2 can operate with no elbow
+     * room at all, but it will be very slow.  For better performance, at
+     * least size-n elbow room is enforced. */
+    ASSERT (iwlen >= pfree + n) ;
+
+#ifndef NDEBUG
+    for (p = 0 ; p < iwlen ; p++) Iw [p] = EMPTY ;
+#endif
+
+    for (k = 0 ; k < n ; k++)
+    {
+       AMD_DEBUG1 (("Construct row/column k= "ID" of A+A'\n", k))  ;
+       p1 = Ap [k] ;
+       p2 = Ap [k+1] ;
+
+       /* construct A+A' */
+       for (p = p1 ; p < p2 ; )
+       {
+           /* scan the upper triangular part of A */
+           j = Ai [p] ;
+           ASSERT (j >= 0 && j < n) ;
+           if (j < k)
+           {
+               /* entry A (j,k) in the strictly upper triangular part */
+               ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
+               ASSERT (Sp [k] < (k == n-1 ? pfree : Pe [k+1])) ;
+               Iw [Sp [j]++] = k ;
+               Iw [Sp [k]++] = j ;
+               p++ ;
+           }
+           else if (j == k)
+           {
+               /* skip the diagonal */
+               p++ ;
+               break ;
+           }
+           else /* j > k */
+           {
+               /* first entry below the diagonal */
+               break ;
+           }
+           /* scan lower triangular part of A, in column j until reaching
+            * row k.  Start where last scan left off. */
+           ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ;
+           pj2 = Ap [j+1] ;
+           for (pj = Tp [j] ; pj < pj2 ; )
+           {
+               i = Ai [pj] ;
+               ASSERT (i >= 0 && i < n) ;
+               if (i < k)
+               {
+                   /* A (i,j) is only in the lower part, not in upper */
+                   ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ;
+                   ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
+                   Iw [Sp [i]++] = j ;
+                   Iw [Sp [j]++] = i ;
+                   pj++ ;
+               }
+               else if (i == k)
+               {
+                   /* entry A (k,j) in lower part and A (j,k) in upper */
+                   pj++ ;
+                   break ;
+               }
+               else /* i > k */
+               {
+                   /* consider this entry later, when k advances to i */
+                   break ;
+               }
+           }
+           Tp [j] = pj ;
+       }
+       Tp [k] = p ;
+    }
+
+    /* clean up, for remaining mismatched entries */
+    for (j = 0 ; j < n ; j++)
+    {
+       for (pj = Tp [j] ; pj < Ap [j+1] ; pj++)
+       {
+           i = Ai [pj] ;
+           ASSERT (i >= 0 && i < n) ;
+           /* A (i,j) is only in the lower part, not in upper */
+           ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ;
+           ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
+           Iw [Sp [i]++] = j ;
+           Iw [Sp [j]++] = i ;
+       }
+    }
+
+#ifndef NDEBUG
+    for (j = 0 ; j < n-1 ; j++) ASSERT (Sp [j] == Pe [j+1]) ;
+    ASSERT (Sp [n-1] == pfree) ;
+#endif
+
+    /* Tp and Sp no longer needed ] */
+
+    /* --------------------------------------------------------------------- */
+    /* order the matrix */
+    /* --------------------------------------------------------------------- */
+
+    AMD_2 (n, Pe, Iw, Len, iwlen, pfree,
+       Nv, Pinv, P, Head, Elen, Degree, W, Control, Info) ;
+}
diff --git a/deal.II/contrib/umfpack/AMD/Source/amd_2.c b/deal.II/contrib/umfpack/AMD/Source/amd_2.c
new file mode 100644 (file)
index 0000000..ca1141e
--- /dev/null
@@ -0,0 +1,1823 @@
+/* ========================================================================= */
+/* === AMD_2 =============================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,  */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README for License.         */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.           */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* AMD_2:  performs the AMD ordering on a symmetric sparse matrix A, followed
+ * by a postordering (via depth-first search) of the assembly tree using the
+ * AMD_postorder routine.
+ */
+
+#include "amd_internal.h"
+
+GLOBAL void AMD_2
+(
+    Int n,             /* A is n-by-n, where n > 0 */
+    Int Pe [ ],                /* Pe [0..n-1]: index in Iw of row i on input */
+    Int Iw [ ],                /* workspace of size iwlen. Iw [0..pfree-1]
+                        * holds the matrix on input */
+    Int Len [ ],       /* Len [0..n-1]: length for row/column i on input */
+    Int iwlen,         /* length of Iw. iwlen >= pfree + n */
+    Int pfree,         /* Iw [pfree ... iwlen-1] is empty on input */
+
+    /* 7 size-n workspaces, not defined on input: */
+    Int Nv [ ],                /* the size of each supernode on output */
+    Int Next [ ],      /* the output inverse permutation */
+    Int Last [ ],      /* the output permutation */
+    Int Head [ ],
+    Int Elen [ ],      /* the size columns of L for each supernode */
+    Int Degree [ ],
+    Int W [ ],
+
+    /* control parameters and output statistics */
+    double Control [ ],        /* array of size AMD_CONTROL */
+    double Info [ ]    /* array of size AMD_INFO */
+)
+{
+
+/*
+ * Given a representation of the nonzero pattern of a symmetric matrix, A, 
+ * (excluding the diagonal) perform an approximate minimum (UMFPACK/MA38-style)
+ * degree ordering to compute a pivot order such that the introduction of
+ * nonzeros (fill-in) in the Cholesky factors A = LL' is kept low.  At each
+ * step, the pivot selected is the one with the minimum UMFAPACK/MA38-style
+ * upper-bound on the external degree.  This routine can optionally perform
+ * aggresive absorption (as done by MC47B in the Harwell Subroutine
+ * Library).
+ * 
+ * The approximate degree algorithm implemented here is the symmetric analog of
+ * the degree update algorithm in MA38 and UMFPACK (the Unsymmetric-pattern
+ * MultiFrontal PACKage, both by Davis and Duff).  The routine is based on the
+ * MA27 minimum degree ordering algorithm by Iain Duff and John Reid.
+ * 
+ * This routine is a translation of the original AMDBAR and MC47B routines,
+ * in Fortran, with the following modifications:
+ * 
+ * (1) dense rows/columns are removed prior to ordering the matrix, and placed
+ *     last in the output order.  The presence of a dense row/column can
+ *     increase the ordering time by up to O(n^2), unless they are removed
+ *     prior to ordering.
+ *
+ * (2) the minimum degree ordering is followed by a postordering (depth-first
+ *     search) of the assembly tree.  Note that mass elimination (discussed
+ *     below) combined with the approximate degree update can lead to the mass
+ *     elimination of nodes with lower exact degree than the current pivot
+ *     element.  No additional fill-in is caused in the representation of the
+ *     Schur complement.  The mass-eliminated nodes merge with the current
+ *     pivot element.  They are ordered prior to the current pivot element.
+ *     Because they can have lower exact degree than the current element, the
+ *     merger of two or more of these nodes in the current pivot element can
+ *     lead to a single element that is not a "fundamental supernode".  The
+ *     diagonal block can have zeros in it.  Thus, the assembly tree used here
+ *     is not guaranteed to be the precise supernodal elemination tree (with
+ *     "funadmental" supernodes), and the postordering performed by this
+ *     routine is not guaranteed to be a precise postordering of the
+ *     elimination tree.
+ *
+ * (3) input parameters are added, to control aggressive absorption and the
+ *     detection of "dense" rows/columns of A.
+ *
+ * (4) additional statistical information is returned, such as the number of
+ *     nonzeros in L, and the flop counts for subsequent LDL' and LU
+ *     factorizations.  These are slight upper bounds, because of the mass
+ *     elimination issue discussed above.
+ *
+ * (5) additional routines are added to interface this routine to MATLAB
+ *     to provide a simple C-callable user-interface, to check inputs for
+ *     errors, compute the symmetry of the pattern of A and the number of
+ *     nonzeros in each row/column of A+A', to compute the pattern of A+A',
+ *     to perform the assembly tree postordering, and to provide debugging
+ *     ouput.  Many of these functions are also provided by the Fortran
+ *     Harwell Subroutine Library routine MC47A.
+ *
+ * (6) both "int" and "long" versions are provided.  In the descriptions below
+ *     and integer is and "int" or "long", depending on which version is
+ *     being used.
+
+ **********************************************************************
+ ***** CAUTION:  ARGUMENTS ARE NOT CHECKED FOR ERRORS ON INPUT.  ******
+ **********************************************************************
+ ** If you want error checking, a more versatile input format, and a **
+ ** simpler user interface, use amd_order or amd_l_order instead.    **
+ ** This routine is not meant to be user-callable.                   **
+ **********************************************************************
+
+ * ----------------------------------------------------------------------------
+ * References:
+ * ----------------------------------------------------------------------------
+ *
+ *  [1] Timothy A. Davis and Iain Duff, "An unsymmetric-pattern multifrontal
+ *     method for sparse LU factorization", SIAM J. Matrix Analysis and
+ *     Applications, vol. 18, no. 1, pp. 140-158.  Discusses UMFPACK / MA38,
+ *     which first introduced the approximate minimum degree used by this
+ *     routine.
+ *
+ *  [2] Patrick Amestoy, Timothy A. Davis, and Iain S. Duff, "An approximate
+ *     minimum degree ordering algorithm," SIAM J. Matrix Analysis and
+ *     Applications, vol. 17, no. 4, pp. 886-905, 1996.  Discusses AMDBAR and
+ *     MC47B, which are the Fortran versions of this routine.
+ *
+ *  [3] Alan George and Joseph Liu, "The evolution of the minimum degree
+ *     ordering algorithm," SIAM Review, vol. 31, no. 1, pp. 1-19, 1989.
+ *     We list below the features mentioned in that paper that this code
+ *     includes:
+ *
+ *     mass elimination:
+ *         Yes.  MA27 relied on supervariable detection for mass elimination.
+ *
+ *     indistinguishable nodes:
+ *         Yes (we call these "supervariables").  This was also in the MA27
+ *         code - although we modified the method of detecting them (the
+ *         previous hash was the true degree, which we no longer keep track
+ *         of).  A supervariable is a set of rows with identical nonzero
+ *         pattern.  All variables in a supervariable are eliminated together.
+ *         Each supervariable has as its numerical name that of one of its
+ *         variables (its principal variable).
+ *
+ *     quotient graph representation:
+ *         Yes.  We use the term "element" for the cliques formed during
+ *         elimination.  This was also in the MA27 code.  The algorithm can
+ *         operate in place, but it will work more efficiently if given some
+ *         "elbow room."
+ *
+ *     element absorption:
+ *         Yes.  This was also in the MA27 code.
+ *
+ *     external degree:
+ *         Yes.  The MA27 code was based on the true degree.
+ *
+ *     incomplete degree update and multiple elimination:
+ *         No.  This was not in MA27, either.  Our method of degree update
+ *         within MC47B is element-based, not variable-based.  It is thus
+ *         not well-suited for use with incomplete degree update or multiple
+ *         elimination.
+ *
+ * Authors, and Copyright (C) 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, x, ok, ndense, ncmpa,
+       dense, aggressive ;
+
+    unsigned Int hash ;            /* unsigned, so that hash % n is well defined.*/
+
+/*
+ * deg:                the degree of a variable or element
+ * degme:      size, |Lme|, of the current element, me (= Degree [me])
+ * dext:       external degree, |Le \ Lme|, of some element e
+ * lemax:      largest |Le| seen so far (called dmax in Fortran version)
+ * e:          an element
+ * elenme:     the length, Elen [me], of element list of pivotal variable
+ * eln:                the length, Elen [...], of an element list
+ * hash:       the computed value of the hash function
+ * i:          a supervariable
+ * ilast:      the entry in a link list preceding i
+ * inext:      the entry in a link list following i
+ * j:          a supervariable
+ * jlast:      the entry in a link list preceding j
+ * jnext:      the entry in a link list, or path, following j
+ * k:          the pivot order of an element or variable
+ * knt1:       loop counter used during element construction
+ * knt2:       loop counter used during element construction
+ * knt3:       loop counter used during compression
+ * lenj:       Len [j]
+ * ln:         length of a supervariable list
+ * me:         current supervariable being eliminated, and the current
+ *                 element created by eliminating that supervariable
+ * mindeg:     current minimum degree
+ * nel:                number of pivots selected so far
+ * nleft:      n - nel, the number of nonpivotal rows/columns remaining
+ * nvi:                the number of variables in a supervariable i (= Nv [i])
+ * nvj:                the number of variables in a supervariable j (= Nv [j])
+ * nvpiv:      number of pivots in current element
+ * slenme:     number of variables in variable list of pivotal variable
+ * wbig:       = INT_MAX - n for the "int" version, LONG_MAX - n for the
+ *                 "long" version.  wflg is not allowed to be >= wbig.
+ * we:         W [e]
+ * wflg:       used for flagging the W array.  See description of Iw.
+ * wnvi:       wflg - Nv [i]
+ * x:          either a supervariable or an element
+ *
+ * ok:         true if supervariable j can be absorbed into i
+ * ndense:     number of "dense" rows/columns
+ * dense:      rows/columns with initial degree > dense are considered "dense"
+ * aggressive: true if aggressive absorption is being performed
+ * ncmpa:      number of garbage collections
+
+ * ----------------------------------------------------------------------------
+ * LOCAL DOUBLES, used for statistical output only (except for alpha):
+ * ----------------------------------------------------------------------------
+ */
+
+    double f, r, ndiv, s, nms_lu, nms_ldl, dmax, alpha, lnz, lnzme ;
+
+/*
+ * f:          nvpiv
+ * r:          degme + nvpiv
+ * ndiv:       number of divisions for LU or LDL' factorizations
+ * s:          number of multiply-subtract pairs for LU factorization, for the
+ *                 current element me
+ * nms_lu      number of multiply-subtract pairs for LU factorization
+ * nms_ldl     number of multiply-subtract pairs for LDL' factorization
+ * dmax:       the largest number of entries in any column of L, including the
+ *                 diagonal
+ * alpha:      "dense" degree ratio
+ * lnz:                the number of nonzeros in L (excluding the diagonal)
+ * lnzme:      the number of nonzeros in L (excl. the diagonal) for the
+ *                 current element me
+
+ * ----------------------------------------------------------------------------
+ * LOCAL "POINTERS" (indices into the Iw array)
+ * ----------------------------------------------------------------------------
+*/
+
+    Int p, p1, p2, p3, p4, pdst, pend, pj, pme, pme1, pme2, pn, psrc ;
+
+/*
+ * Any parameter (Pe [...] or pfree) or local variable starting with "p" (for
+ * Pointer) is an index into Iw, and all indices into Iw use variables starting
+ * with "p."  The only exception to this rule is the iwlen input argument.
+ *
+ * p:           pointer into lots of things
+ * p1:          Pe [i] for some variable i (start of element list)
+ * p2:          Pe [i] + Elen [i] -  1 for some variable i
+ * p3:          index of first supervariable in clean list
+ * p4:         
+ * pdst:        destination pointer, for compression
+ * pend:        end of memory to compress
+ * pj:          pointer into an element or variable
+ * pme:         pointer into the current element (pme1...pme2)
+ * pme1:        the current element, me, is stored in Iw [pme1...pme2]
+ * pme2:        the end of the current element
+ * pn:          pointer into a "clean" variable, also used to compress
+ * psrc:        source pointer, for compression
+*/
+
+/* ========================================================================= */
+/*  INITIALIZATIONS */
+/* ========================================================================= */
+
+    /* Note that this restriction on iwlen is slightly more restrictive than
+     * what is actually required in AMD_2.  AMD_2 can operate with no elbow
+     * room at all, but it will be slow.  For better performance, at least
+     * size-n elbow room is enforced. */
+    ASSERT (iwlen >= pfree + n) ;
+    ASSERT (n > 0) ;
+
+    /* initialize output statistics */
+    lnz = 0 ;
+    ndiv = 0 ;
+    nms_lu = 0 ;
+    nms_ldl = 0 ;
+    dmax = 1 ;
+    me = EMPTY ;
+
+    wflg = 2 ;
+    mindeg = 0 ;
+    ncmpa = 0 ;
+    nel = 0 ;
+    lemax = 0 ;                /* this is called dmax in the Fortran version */
+
+#ifdef TEST_FOR_INTEGER_OVERFLOW
+    /* for testing only */
+    wbig = 3*n ;
+#else
+    /* normal operation */
+    wbig = Int_MAX - n ;
+#endif
+
+    /* get control parameters */
+    if (Control != (double *) NULL)
+    {
+       alpha = Control [AMD_DENSE] ;
+       aggressive = (Control [AMD_AGGRESSIVE] != 0) ;
+    }
+    else
+    {
+       alpha = AMD_DEFAULT_DENSE ;
+       aggressive = AMD_DEFAULT_AGGRESSIVE ;
+    }
+    if (alpha < 0)
+    {
+       /* no dense rows/columns */
+       dense = n ;
+    }
+    else
+    {
+       dense = alpha * sqrt ((double) n) ;
+    }
+    dense = MAX (16, dense) ;
+    dense = MIN (n,  dense) ;
+    AMD_DEBUG1 (("AMD (debug), alpha %g, aggr. "ID"\n", alpha, aggressive)) ;
+
+    for (i = 0 ; i < n ; i++)
+    {
+       Last [i] = EMPTY ;
+       Head [i] = EMPTY ;
+       Next [i] = EMPTY ;
+       /* if seperate Hhead array is used for hash buckets: *
+       Hhead [i] = EMPTY ;
+       */
+       Nv [i] = 1 ;
+       W [i] = 1 ;
+       Elen [i] = 0 ;
+       Degree [i] = Len [i] ;
+    }
+
+#ifndef NDEBUG
+    AMD_DEBUG1 (("\n======Nel "ID"\n", nel)) ;
+    AMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next, Last,
+               Head, Elen, Degree, W, -1) ;
+#endif
+
+    /* --------------------------------------------------------------------- */
+    /* initialize degree lists and eliminate dense and empty rows */
+    /* --------------------------------------------------------------------- */
+
+    ndense = 0 ;
+
+    /* for (i = n-1 ; i >= 0 ; i--) */
+    for (i = 0 ; i < n ; i++)
+    {
+       deg = Degree [i] ;
+       ASSERT (deg >= 0 && deg < n) ;
+       if (deg == 0)
+       {
+
+           /* -------------------------------------------------------------
+            * we have a variable that can be eliminated at once because
+            * there is no off-diagonal non-zero in its row.  Note that
+            * Nv [i] = 1 for an empty variable i.  It is treated just
+            * the same as an eliminated element i.
+            * ------------------------------------------------------------- */
+
+           Elen [i] = FLIP (1) ;
+           nel++ ;
+           Pe [i] = EMPTY ;
+           W [i] = 0 ;
+
+       }
+       else if (deg > dense)
+       {
+
+           /* -------------------------------------------------------------
+            * Dense variables are not treated as elements, but as unordered,
+            * non-principal variables that have no parent.  They do not take
+            * part in the postorder, since Nv [i] = 0.  Note that the Fortran
+            * version does not have this option.
+            * ------------------------------------------------------------- */
+
+           AMD_DEBUG1 (("Dense node "ID" degree "ID"\n", i, deg)) ;
+           ndense++ ;
+           Nv [i] = 0 ;                /* do not postorder this node */
+           Elen [i] = EMPTY ;
+           nel++ ;
+           Pe [i] = EMPTY ;
+
+       }
+       else
+       {
+
+           /* -------------------------------------------------------------
+            * place i in the degree list corresponding to its degree
+            * ------------------------------------------------------------- */
+
+           inext = Head [deg] ;
+           ASSERT (inext >= EMPTY && inext < n) ;
+           if (inext != EMPTY) Last [inext] = i ;
+           Next [i] = inext ;
+           Head [deg] = i ;
+
+       }
+    }
+
+/* ========================================================================= */
+/* WHILE (selecting pivots) DO */
+/* ========================================================================= */
+
+    while (nel < n)
+    {
+
+#ifndef NDEBUG
+       AMD_DEBUG1 (("\n======Nel "ID"\n", nel)) ;
+       if (AMD_debug >= 2) AMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next,
+           Last, Head, Elen, Degree, W, nel) ;
+#endif
+
+/* ========================================================================= */
+/* GET PIVOT OF MINIMUM DEGREE */
+/* ========================================================================= */
+
+       /* ----------------------------------------------------------------- */
+       /* find next supervariable for elimination */
+       /* ----------------------------------------------------------------- */
+
+       ASSERT (mindeg >= 0 && mindeg < n) ;
+       for (deg = mindeg ; deg < n ; deg++)
+       {
+           me = Head [deg] ;
+           if (me != EMPTY) break ;
+       }
+       mindeg = deg ;
+       ASSERT (me >= 0 && me < n) ;
+       AMD_DEBUG1 (("=================me: "ID"\n", me)) ;
+
+       /* ----------------------------------------------------------------- */
+       /* remove chosen variable from link list */
+       /* ----------------------------------------------------------------- */
+
+       inext = Next [me] ;
+       ASSERT (inext >= EMPTY && inext < n) ;
+       if (inext != EMPTY) Last [inext] = EMPTY ;
+       Head [deg] = inext ;
+
+       /* ----------------------------------------------------------------- */
+       /* me represents the elimination of pivots nel to nel+Nv[me]-1. */
+       /* place me itself as the first in this set. */
+       /* ----------------------------------------------------------------- */
+
+       elenme = Elen [me] ;
+       nvpiv = Nv [me] ;
+       ASSERT (nvpiv > 0) ;
+       nel += nvpiv ;
+
+/* ========================================================================= */
+/* CONSTRUCT NEW ELEMENT */
+/* ========================================================================= */
+
+       /* -----------------------------------------------------------------
+        * At this point, me is the pivotal supervariable.  It will be
+        * converted into the current element.  Scan list of the pivotal
+        * supervariable, me, setting tree pointers and constructing new list
+        * of supervariables for the new element, me.  p is a pointer to the
+        * current position in the old list.
+        * ----------------------------------------------------------------- */
+
+       /* flag the variable "me" as being in Lme by negating Nv [me] */
+       Nv [me] = -nvpiv ;
+       degme = 0 ;
+       ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ;
+
+       if (elenme == 0)
+       {
+
+           /* ------------------------------------------------------------- */
+           /* construct the new element in place */
+           /* ------------------------------------------------------------- */
+
+           pme1 = Pe [me] ;
+           pme2 = pme1 - 1 ;
+
+           for (p = pme1 ; p <= pme1 + Len [me] - 1 ; p++)
+           {
+               i = Iw [p] ;
+               ASSERT (i >= 0 && i < n && Nv [i] >= 0) ;
+               nvi = Nv [i] ;
+               if (nvi > 0)
+               {
+
+                   /* ----------------------------------------------------- */
+                   /* i is a principal variable not yet placed in Lme. */
+                   /* store i in new list */
+                   /* ----------------------------------------------------- */
+
+                    /* flag i as being in Lme by negating Nv [i] */
+                   degme += nvi ;
+                   Nv [i] = -nvi ;
+                   Iw [++pme2] = i ;
+
+                   /* ----------------------------------------------------- */
+                   /* remove variable i from degree list. */
+                   /* ----------------------------------------------------- */
+
+                   ilast = Last [i] ;
+                   inext = Next [i] ;
+                   ASSERT (ilast >= EMPTY && ilast < n) ;
+                   ASSERT (inext >= EMPTY && inext < n) ;
+                   if (inext != EMPTY) Last [inext] = ilast ;
+                   if (ilast != EMPTY)
+                   {
+                       Next [ilast] = inext ;
+                   }
+                   else
+                   {
+                        /* i is at the head of the degree list */
+                       ASSERT (Degree [i] >= 0 && Degree [i] < n) ;
+                       Head [Degree [i]] = inext ;
+                   }
+               }
+           }
+       }
+       else
+       {
+
+           /* ------------------------------------------------------------- */
+           /* construct the new element in empty space, Iw [pfree ...] */
+           /* ------------------------------------------------------------- */
+
+           p = Pe [me] ;
+           pme1 = pfree ;
+           slenme = Len [me] - elenme ;
+
+           for (knt1 = 1 ; knt1 <= elenme + 1 ; knt1++)
+           {
+
+               if (knt1 > elenme)
+               {
+                   /* search the supervariables in me. */
+                   e = me ;
+                   pj = p ;
+                   ln = slenme ;
+                   AMD_DEBUG2 (("Search sv: "ID" "ID" "ID"\n", me,pj,ln)) ;
+               }
+               else
+               {
+                    /* search the elements in me. */
+                   e = Iw [p++] ;
+                   ASSERT (e >= 0 && e < n) ;
+                   pj = Pe [e] ;
+                   ln = Len [e] ;
+                   AMD_DEBUG2 (("Search element e "ID" in me "ID"\n", e,me)) ;
+                   ASSERT (Elen [e] < EMPTY && W [e] > 0 && pj >= 0) ;
+               }
+               ASSERT (ln >= 0 && (ln == 0 || (pj >= 0 && pj < iwlen))) ;
+
+               /* ---------------------------------------------------------
+                * search for different supervariables and add them to the
+                * new list, compressing when necessary. this loop is
+                * executed once for each element in the list and once for
+                * all the supervariables in the list.
+                * --------------------------------------------------------- */
+
+               for (knt2 = 1 ; knt2 <= ln ; knt2++)
+               {
+                   i = Iw [pj++] ;
+                   ASSERT (i >= 0 && i < n && (i == me || Elen [i] >= EMPTY));
+                   nvi = Nv [i] ;
+                   AMD_DEBUG2 ((": "ID" "ID" "ID" "ID"\n",
+                               i, Elen [i], Nv [i], wflg)) ;
+
+                   if (nvi > 0)
+                   {
+
+                       /* ------------------------------------------------- */
+                       /* compress Iw, if necessary */
+                       /* ------------------------------------------------- */
+
+                       if (pfree >= iwlen)
+                       {
+
+                           AMD_DEBUG1 (("GARBAGE COLLECTION\n")) ;
+
+                           /* prepare for compressing Iw by adjusting pointers
+                            * and lengths so that the lists being searched in
+                            * the inner and outer loops contain only the
+                            * remaining entries. */
+
+                           Pe [me] = p ;
+                           Len [me] -= knt1 ;
+                            /* check if nothing left of supervariable me */
+                           if (Len [me] == 0) Pe [me] = EMPTY ;
+                           Pe [e] = pj ;
+                           Len [e] = ln - knt2 ;
+                            /* nothing left of element e */
+                           if (Len [e] == 0) Pe [e] = EMPTY ;
+
+                           ncmpa++ ;   /* one more garbage collection */
+
+                            /* store first entry of each object in Pe */
+                            /* FLIP the first entry in each object */
+                           for (j = 0 ; j < n ; j++)
+                           {
+                               pn = Pe [j] ;
+                               if (pn >= 0)
+                               {
+                                   ASSERT (pn >= 0 && pn < iwlen) ;
+                                   Pe [j] = Iw [pn] ;
+                                   Iw [pn] = FLIP (j) ;
+                               }
+                           }
+
+                            /* psrc/pdst point to source/destination */
+                           psrc = 0 ;
+                           pdst = 0 ;
+                           pend = pme1 - 1 ;
+
+                           while (psrc <= pend)
+                           {
+                               /* search for next FLIP'd entry */
+                               j = FLIP (Iw [psrc++]) ;
+                               if (j >= 0)
+                               {
+                                   AMD_DEBUG2 (("Got object j: "ID"\n", j)) ;
+                                   Iw [pdst] = Pe [j] ;
+                                   Pe [j] = pdst++ ;
+                                   lenj = Len [j] ;
+                                   /* copy from source to destination */
+                                   for (knt3 = 0 ; knt3 <= lenj - 2 ; knt3++)
+                                   {
+                                       Iw [pdst++] = Iw [psrc++] ;
+                                   }
+                               }
+                           }
+
+                            /* move the new partially-constructed element */
+                           p1 = pdst ;
+                           for (psrc = pme1 ; psrc <= pfree-1 ; psrc++)
+                           {
+                               Iw [pdst++] = Iw [psrc] ;
+                           }
+                           pme1 = p1 ;
+                           pfree = pdst ;
+                           pj = Pe [e] ;
+                           p = Pe [me] ;
+
+                       }
+
+                       /* ------------------------------------------------- */
+                       /* i is a principal variable not yet placed in Lme */
+                       /* store i in new list */
+                       /* ------------------------------------------------- */
+
+                        /* flag i as being in Lme by negating Nv [i] */
+                       degme += nvi ;
+                       Nv [i] = -nvi ;
+                       Iw [pfree++] = i ;
+                       AMD_DEBUG2 (("     s: "ID"     nv "ID"\n", i, Nv [i]));
+
+                       /* ------------------------------------------------- */
+                       /* remove variable i from degree link list */
+                       /* ------------------------------------------------- */
+
+                       ilast = Last [i] ;
+                       inext = Next [i] ;
+                       ASSERT (ilast >= EMPTY && ilast < n) ;
+                       ASSERT (inext >= EMPTY && inext < n) ;
+                       if (inext != EMPTY) Last [inext] = ilast ;
+                       if (ilast != EMPTY)
+                       {
+                           Next [ilast] = inext ;
+                       }
+                       else
+                       {
+                            /* i is at the head of the degree list */
+                           ASSERT (Degree [i] >= 0 && Degree [i] < n) ;
+                           Head [Degree [i]] = inext ;
+                       }
+                   }
+               }
+
+               if (e != me)
+               {
+                    /* set tree pointer and flag to indicate element e is
+                     * absorbed into new element me (the parent of e is me) */
+                   AMD_DEBUG1 ((" Element "ID" => "ID"\n", e, me)) ;
+                   Pe [e] = FLIP (me) ;
+                   W [e] = 0 ;
+               }
+           }
+
+           pme2 = pfree - 1 ;
+       }
+
+       /* ----------------------------------------------------------------- */
+       /* me has now been converted into an element in Iw [pme1..pme2] */
+       /* ----------------------------------------------------------------- */
+
+        /* degme holds the external degree of new element */
+       Degree [me] = degme ;
+       Pe [me] = pme1 ;
+       Len [me] = pme2 - pme1 + 1 ;
+       ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ;
+
+       Elen [me] = FLIP (nvpiv + degme) ;
+        /* FLIP (Elen (me)) is now the degree of pivot (including
+        * diagonal part). */
+
+#ifndef NDEBUG
+       AMD_DEBUG2 (("New element structure: length= "ID"\n", pme2-pme1+1)) ;
+       for (pme = pme1 ; pme <= pme2 ; pme++) AMD_DEBUG3 ((" "ID"", Iw[pme]));
+       AMD_DEBUG3 (("\n")) ;
+#endif
+
+       /* ----------------------------------------------------------------- */
+       /* make sure that wflg is not too large. */
+       /* ----------------------------------------------------------------- */
+
+       /* With the current value of wflg, wflg+n must not cause integer
+        * overflow */
+
+       if (wflg >= wbig)
+       {
+           for (x = 0 ; x < n ; x++)
+           {
+               if (W [x] != 0) W [x] = 1 ;
+           }
+           wflg = 2 ;
+       }
+
+/* ========================================================================= */
+/* COMPUTE (W [e] - wflg) = |Le\Lme| FOR ALL ELEMENTS */
+/* ========================================================================= */
+
+       /* -----------------------------------------------------------------
+        * Scan 1:  compute the external degrees of previous elements with
+        * respect to the current element.  That is:
+        *       (W [e] - wflg) = |Le \ Lme|
+        * for each element e that appears in any supervariable in Lme.  The
+        * notation Le refers to the pattern (list of supervariables) of a
+        * previous element e, where e is not yet absorbed, stored in
+        * Iw [Pe [e] + 1 ... Pe [e] + Iw [Pe [e]]].  The notation Lme
+        * refers to the pattern of the current element (stored in
+        * Iw [pme1..pme2]).   If aggressive absorption is enabled, and
+        * (W [e] - wflg) becomes zero, then the element e will be absorbed
+        * in Scan 2.
+        * ----------------------------------------------------------------- */
+
+       AMD_DEBUG2 (("me: ")) ;
+       for (pme = pme1 ; pme <= pme2 ; pme++)
+       {
+           i = Iw [pme] ;
+           ASSERT (i >= 0 && i < n) ;
+           eln = Elen [i] ;
+           AMD_DEBUG3 ((""ID" Elen "ID": \n", i, eln)) ;
+           if (eln > 0)
+           {
+                /* note that Nv [i] has been negated to denote i in Lme: */
+               nvi = -Nv [i] ;
+               ASSERT (nvi > 0 && Pe [i] >= 0 && Pe [i] < iwlen) ;
+               wnvi = wflg - nvi ;
+               for (p = Pe [i] ; p <= Pe [i] + eln - 1 ; p++)
+               {
+                   e = Iw [p] ;
+                   ASSERT (e >= 0 && e < n) ;
+                   we = W [e] ;
+                   AMD_DEBUG4 (("    e "ID" we "ID" ", e, we)) ;
+                   if (we >= wflg)
+                   {
+                        /* unabsorbed element e has been seen in this loop */
+                       AMD_DEBUG4 (("    unabsorbed, first time seen")) ;
+                       we -= nvi ;
+                   }
+                   else if (we != 0)
+                   {
+                        /* e is an unabsorbed element */
+                        /* this is the first we have seen e in all of Scan 1 */
+                       AMD_DEBUG4 (("    unabsorbed")) ;
+                       we = Degree [e] + wnvi ;
+                   }
+                   AMD_DEBUG4 (("\n")) ;
+                   W [e] = we ;
+               }
+           }
+       }
+       AMD_DEBUG2 (("\n")) ;
+
+/* ========================================================================= */
+/* DEGREE UPDATE AND ELEMENT ABSORPTION */
+/* ========================================================================= */
+
+       /* -----------------------------------------------------------------
+        * Scan 2:  for each i in Lme, sum up the degree of Lme (which is
+        * degme), plus the sum of the external degrees of each Le for the
+        * elements e appearing within i, plus the supervariables in i.
+        * Place i in hash list.
+        * ----------------------------------------------------------------- */
+
+       for (pme = pme1 ; pme <= pme2 ; pme++)
+       {
+           i = Iw [pme] ;
+           ASSERT (i >= 0 && i < n && Nv [i] < 0 && Elen [i] >= 0) ;
+           AMD_DEBUG2 (("Updating: i "ID" "ID" "ID"\n", i, Elen[i], Len [i]));
+           p1 = Pe [i] ;
+           p2 = p1 + Elen [i] - 1 ;
+           pn = p1 ;
+           hash = 0 ;
+           deg = 0 ;
+           ASSERT (p1 >= 0 && p1 < iwlen && p2 >= -1 && p2 < iwlen) ;
+
+           /* ------------------------------------------------------------- */
+           /* scan the element list associated with supervariable i */
+           /* ------------------------------------------------------------- */
+
+            /* UMFPACK/MA38-style approximate degree: */
+           if (aggressive)
+           {
+               for (p = p1 ; p <= p2 ; p++)
+               {
+                   e = Iw [p] ;
+                   ASSERT (e >= 0 && e < n) ;
+                   we = W [e] ;
+                   if (we != 0)
+                   {
+                       /* e is an unabsorbed element */
+                       /* dext = | Le \ Lme | */
+                       dext = we - wflg ;
+                       if (dext > 0)
+                       {
+                           deg += dext ;
+                           Iw [pn++] = e ;
+                           hash += e ;
+                           AMD_DEBUG4 ((" e: "ID" hash = "ID"\n",e,hash)) ;
+                       }
+                       else
+                       {
+                           /* external degree of e is zero, absorb e into me*/
+                           AMD_DEBUG1 ((" Element "ID" =>"ID" (aggressive)\n",
+                               e, me)) ;
+                           ASSERT (dext == 0) ;
+                           Pe [e] = FLIP (me) ;
+                           W [e] = 0 ;
+                       }
+                   }
+               }
+           }
+           else
+           {
+               for (p = p1 ; p <= p2 ; p++)
+               {
+                   e = Iw [p] ;
+                   ASSERT (e >= 0 && e < n) ;
+                   we = W [e] ;
+                   if (we != 0)
+                   {
+                       /* e is an unabsorbed element */
+                       dext = we - wflg ;
+                       ASSERT (dext >= 0) ;
+                       deg += dext ;
+                       Iw [pn++] = e ;
+                       hash += e ;
+                       AMD_DEBUG4 (("  e: "ID" hash = "ID"\n",e,hash)) ;
+                   }
+               }
+           }
+
+            /* count the number of elements in i (including me): */
+           Elen [i] = pn - p1 + 1 ;
+
+           /* ------------------------------------------------------------- */
+           /* scan the supervariables in the list associated with i */
+           /* ------------------------------------------------------------- */
+
+           /* The bulk of the AMD run time is typically spent in this loop,
+            * particularly if the matrix has many dense rows that are not
+            * removed prior to ordering. */
+           p3 = pn ;
+           p4 = p1 + Len [i] ;
+           for (p = p2 + 1 ; p < p4 ; p++)
+           {
+               j = Iw [p] ;
+               ASSERT (j >= 0 && j < n) ;
+               nvj = Nv [j] ;
+               if (nvj > 0)
+               {
+                    /* j is unabsorbed, and not in Lme. */
+                    /* add to degree and add to new list */
+                   deg += nvj ;
+                   Iw [pn++] = j ;
+                   hash += j ;
+                   AMD_DEBUG4 (("  s: "ID" hash "ID" Nv[j]= "ID"\n",
+                               j, hash, nvj)) ;
+               }
+           }
+
+           /* ------------------------------------------------------------- */
+           /* update the degree and check for mass elimination */
+           /* ------------------------------------------------------------- */
+
+           /* with aggressive absorption, deg==0 is identical to the 
+            * Elen [i] == 1 && p3 == pn test, below. */
+           ASSERT (IMPLIES (aggressive, (deg==0) == (Elen[i]==1 && p3==pn))) ;
+
+           if (Elen [i] == 1 && p3 == pn)
+           {
+
+               /* --------------------------------------------------------- */
+               /* mass elimination */
+               /* --------------------------------------------------------- */
+
+               /* There is nothing left of this node except for an edge to
+                * the current pivot element.  Elen [i] is 1, and there are
+                * no variables adjacent to node i.  Absorb i into the
+                * current pivot element, me.  Note that if there are two or
+                * more mass eliminations, fillin due to mass elimination is
+                * possible within the nvpiv-by-nvpiv pivot block.  It is this
+                * step that causes AMD's analysis to be an upper bound.
+                *
+                * The reason is that the selected pivot has a lower
+                * approximate degree than the true degree of the two mass
+                * eliminated nodes.  There is no edge between the two mass
+                * eliminated nodes.  They are merged with the current pivot
+                * anyway.
+                *
+                * No fillin occurs in the Schur complement, in any case,
+                * and this effect does not decrease the quality of the
+                * ordering itself, just the quality of the nonzero and
+                * flop count analysis.  It also means that the post-ordering
+                * is not an exact elimination tree post-ordering. */
+
+               AMD_DEBUG1 (("  MASS i "ID" => parent e "ID"\n", i, me)) ;
+               Pe [i] = FLIP (me) ;
+               nvi = -Nv [i] ;
+               degme -= nvi ;
+               nvpiv += nvi ;
+               nel += nvi ;
+               Nv [i] = 0 ;
+               Elen [i] = EMPTY ;
+
+           }
+           else
+           {
+
+               /* --------------------------------------------------------- */
+               /* update the upper-bound degree of i */
+               /* --------------------------------------------------------- */
+
+                /* the following degree does not yet include the size
+                 * of the current element, which is added later: */
+
+               Degree [i] = MIN (Degree [i], deg) ;
+
+               /* --------------------------------------------------------- */
+               /* add me to the list for i */
+               /* --------------------------------------------------------- */
+
+                /* move first supervariable to end of list */
+               Iw [pn] = Iw [p3] ;
+                /* move first element to end of element part of list */
+               Iw [p3] = Iw [p1] ;
+                /* add new element, me, to front of list. */
+               Iw [p1] = me ;
+                /* store the new length of the list in Len [i] */
+               Len [i] = pn - p1 + 1 ;
+
+               /* --------------------------------------------------------- */
+               /* place in hash bucket.  Save hash key of i in Last [i]. */
+               /* --------------------------------------------------------- */
+
+               /* NOTE: this can fail if hash is negative, because the ANSI C
+                * standard does not define a % b when a and/or b are negative.
+                * That's why hash is defined as an unsigned Int, to avoid this
+                * problem. */
+               hash = hash % n ;
+               ASSERT (((Int) hash) >= 0 && ((Int) hash) < n) ;
+
+               /* if the Hhead array is not used: */
+               j = Head [hash] ;
+               if (j <= EMPTY)
+               {
+                   /* degree list is empty, hash head is FLIP (j) */
+                   Next [i] = FLIP (j) ;
+                   Head [hash] = FLIP (i) ;
+               }
+               else
+               {
+                   /* degree list is not empty, use Last [Head [hash]] as
+                    * hash head. */
+                   Next [i] = Last [j] ;
+                   Last [j] = i ;
+               }
+
+               /* if a seperate Hhead array is used: *
+               Next [i] = Hhead [hash] ;
+               Hhead [hash] = i ;
+               */
+
+               Last [i] = hash ;
+           }
+       }
+
+       Degree [me] = degme ;
+
+       /* ----------------------------------------------------------------- */
+       /* Clear the counter array, W [...], by incrementing wflg. */
+       /* ----------------------------------------------------------------- */
+
+        /* make sure that wflg+n does not cause integer overflow */
+       lemax =  MAX (lemax, degme) ;
+       wflg += lemax ;
+       if (wflg >= wbig)
+       {
+           for (x = 0 ; x < n ; x++)
+           {
+               if (W [x] != 0) W [x] = 1 ;
+           }
+           wflg = 2 ;
+       }
+        /*  at this point, W [0..n-1] < wflg holds */
+
+/* ========================================================================= */
+/* SUPERVARIABLE DETECTION */
+/* ========================================================================= */
+
+       AMD_DEBUG1 (("Detecting supervariables:\n")) ;
+       for (pme = pme1 ; pme <= pme2 ; pme++)
+       {
+           i = Iw [pme] ;
+           ASSERT (i >= 0 && i < n) ;
+           AMD_DEBUG2 (("Consider i "ID" nv "ID"\n", i, Nv [i])) ;
+           if (Nv [i] < 0)
+           {
+                /* i is a principal variable in Lme */
+
+               /* ---------------------------------------------------------
+                * examine all hash buckets with 2 or more variables.  We do
+                * this by examing all unique hash keys for supervariables in
+                * the pattern Lme of the current element, me
+                * --------------------------------------------------------- */
+
+                /* let i = head of hash bucket, and empty the hash bucket */
+               ASSERT (Last [i] >= 0 && Last [i] < n) ;
+               hash = Last [i] ;
+
+               /* if Hhead array is not used: */
+               j = Head [hash] ;
+               if (j == EMPTY)
+               {
+                   /* hash bucket and degree list are both empty */
+                   i = EMPTY ;
+               }
+               else if (j < EMPTY)
+               {
+                   /* degree list is empty */
+                   i = FLIP (j) ;
+                   Head [hash] = EMPTY ;
+               }
+               else
+               {
+                   /* degree list is not empty, restore Last [j] of head j */
+                   i = Last [j] ;
+                   Last [j] = EMPTY ;
+               }
+
+               /* if seperate Hhead array is used: *
+               i = Hhead [hash] ;
+               Hhead [hash] = EMPTY ;
+               */
+
+               ASSERT (i >= EMPTY && i < n) ;
+               AMD_DEBUG2 (("----i "ID" hash "ID"\n", i, hash)) ;
+
+               while (i != EMPTY && Next [i] != EMPTY)
+               {
+
+                   /* -----------------------------------------------------
+                    * this bucket has one or more variables following i.
+                    * scan all of them to see if i can absorb any entries
+                    * that follow i in hash bucket.  Scatter i into w.
+                    * ----------------------------------------------------- */
+
+                   ln = Len [i] ;
+                   eln = Elen [i] ;
+                   ASSERT (ln >= 0 && eln >= 0) ;
+                   ASSERT (Pe [i] >= 0 && Pe [i] < iwlen) ;
+                    /* do not flag the first element in the list (me) */
+                   for (p = Pe [i] + 1 ; p <= Pe [i] + ln - 1 ; p++)
+                   {
+                       ASSERT (Iw [p] >= 0 && Iw [p] < n) ;
+                       W [Iw [p]] = wflg ;
+                   }
+
+                   /* ----------------------------------------------------- */
+                   /* scan every other entry j following i in bucket */
+                   /* ----------------------------------------------------- */
+
+                   jlast = i ;
+                   j = Next [i] ;
+                   ASSERT (j >= EMPTY && j < n) ;
+
+                   while (j != EMPTY)
+                   {
+                       /* ------------------------------------------------- */
+                       /* check if j and i have identical nonzero pattern */
+                       /* ------------------------------------------------- */
+
+                       AMD_DEBUG3 (("compare i "ID" and j "ID"\n", i,j)) ;
+
+                       /* check if i and j have the same Len and Elen */
+                       ASSERT (Len [j] >= 0 && Elen [j] >= 0) ;
+                       ASSERT (Pe [j] >= 0 && Pe [j] < iwlen) ;
+                       ok = (Len [j] == ln) && (Elen [j] == eln) ;
+                        /* skop the first element in the list (me) */
+                       for (p = Pe [j] + 1 ; ok && p <= Pe [j] + ln - 1 ; p++)
+                       {
+                           ASSERT (Iw [p] >= 0 && Iw [p] < n) ;
+                           if (W [Iw [p]] != wflg) ok = 0 ;
+                       }
+                       if (ok)
+                       {
+                           /* --------------------------------------------- */
+                           /* found it!  j can be absorbed into i */
+                           /* --------------------------------------------- */
+
+                           AMD_DEBUG1 (("found it! j "ID" => i "ID"\n", j,i));
+                           Pe [j] = FLIP (i) ;
+                           /* both Nv [i] and Nv [j] are negated since they */
+                           /* are in Lme, and the absolute values of each */
+                           /* are the number of variables in i and j: */
+                           Nv [i] += Nv [j] ;
+                           Nv [j] = 0 ;
+                           Elen [j] = EMPTY ;
+                           /* delete j from hash bucket */
+                           ASSERT (j != Next [j]) ;
+                           j = Next [j] ;
+                           Next [jlast] = j ;
+
+                       }
+                       else
+                       {
+                           /* j cannot be absorbed into i */
+                           jlast = j ;
+                           ASSERT (j != Next [j]) ;
+                           j = Next [j] ;
+                       }
+                       ASSERT (j >= EMPTY && j < n) ;
+                   }
+
+                   /* -----------------------------------------------------
+                    * no more variables can be absorbed into i
+                    * go to next i in bucket and clear flag array
+                    * ----------------------------------------------------- */
+
+                   wflg++ ;
+                   i = Next [i] ;
+                   ASSERT (i >= EMPTY && i < n) ;
+
+               }
+           }
+       }
+       AMD_DEBUG2 (("detect done\n")) ;
+
+/* ========================================================================= */
+/* RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVARIABLES FROM ELEMENT */
+/* ========================================================================= */
+
+       p = pme1 ;
+       nleft = n - nel ;
+       for (pme = pme1 ; pme <= pme2 ; pme++)
+       {
+           i = Iw [pme] ;
+           ASSERT (i >= 0 && i < n) ;
+           nvi = -Nv [i] ;
+           AMD_DEBUG3 (("Restore i "ID" "ID"\n", i, nvi)) ;
+           if (nvi > 0)
+           {
+                /* i is a principal variable in Lme */
+                /* restore Nv [i] to signify that i is principal */
+               Nv [i] = nvi ;
+
+               /* --------------------------------------------------------- */
+               /* compute the external degree (add size of current element) */
+               /* --------------------------------------------------------- */
+
+               deg = Degree [i] + degme - nvi ;
+               deg = MIN (deg, nleft - nvi) ;
+               ASSERT (IMPLIES (aggressive, deg > 0) && deg >= 0 && deg < n) ;
+
+               /* --------------------------------------------------------- */
+               /* place the supervariable at the head of the degree list */
+               /* --------------------------------------------------------- */
+
+               inext = Head [deg] ;
+               ASSERT (inext >= EMPTY && inext < n) ;
+               if (inext != EMPTY) Last [inext] = i ;
+               Next [i] = inext ;
+               Last [i] = EMPTY ;
+               Head [deg] = i ;
+
+               /* --------------------------------------------------------- */
+               /* save the new degree, and find the minimum degree */
+               /* --------------------------------------------------------- */
+
+               mindeg = MIN (mindeg, deg) ;
+               Degree [i] = deg ;
+
+               /* --------------------------------------------------------- */
+               /* place the supervariable in the element pattern */
+               /* --------------------------------------------------------- */
+
+               Iw [p++] = i ;
+
+           }
+       }
+       AMD_DEBUG2 (("restore done\n")) ;
+
+/* ========================================================================= */
+/* FINALIZE THE NEW ELEMENT */
+/* ========================================================================= */
+
+       AMD_DEBUG2 (("ME = "ID" DONE\n", me)) ;
+       Nv [me] = nvpiv ;
+        /* save the length of the list for the new element me */
+       Len [me] = p - pme1 ;
+       if (Len [me] == 0)
+       {
+            /* there is nothing left of the current pivot element */
+           /* it is a root of the assembly tree */
+           Pe [me] = EMPTY ;
+           W [me] = 0 ;
+       }
+       if (elenme != 0)
+       {
+           /* element was not constructed in place: deallocate part of */
+           /* it since newly nonprincipal variables may have been removed */
+           pfree = p ;
+       }
+
+       /* The new element has nvpiv pivots and the size of the contribution
+        * block for a multifrontal method is degme-by-degme, not including
+        * the "dense" rows/columns.  If the "dense" rows/columns are included,
+        * the frontal matrix is no larger than
+        * (degme+ndense)-by-(degme+ndense).
+        */
+
+       if (Info != (double *) NULL)
+       {
+           f = nvpiv ;
+           r = degme + ndense ;
+           dmax = MAX (dmax, f + r) ;
+
+           /* number of nonzeros in L (excluding the diagonal) */
+           lnzme = f*r + (f-1)*f/2 ;
+           lnz += lnzme ;
+
+           /* number of divide operations for LDL' and for LU */
+           ndiv += lnzme ;
+
+           /* number of multiply-subtract pairs for LU */
+           s = f*r*r + r*(f-1)*f + (f-1)*f*(2*f-1)/6 ;
+           nms_lu += s ;
+
+           /* number of multiply-subtract pairs for LDL' */
+           nms_ldl += (s + lnzme)/2 ;
+       }
+
+#ifndef NDEBUG
+       AMD_DEBUG2 (("finalize done nel "ID" n "ID"\n   ::::\n", nel, n)) ;
+       for (pme = Pe [me] ; pme <= Pe [me] + Len [me] - 1 ; pme++)
+       {
+             AMD_DEBUG3 ((" "ID"", Iw [pme])) ;
+       }
+       AMD_DEBUG3 (("\n")) ;
+#endif
+
+    }
+
+/* ========================================================================= */
+/* DONE SELECTING PIVOTS */
+/* ========================================================================= */
+
+    if (Info != (double *) NULL)
+    {
+
+       /* count the work to factorize the ndense-by-ndense submatrix */
+       f = ndense ;
+       dmax = MAX (dmax, (double) ndense) ;
+
+       /* number of nonzeros in L (excluding the diagonal) */
+       lnzme = (f-1)*f/2 ;
+       lnz += lnzme ;
+
+       /* number of divide operations for LDL' and for LU */
+       ndiv += lnzme ;
+
+       /* number of multiply-subtract pairs for LU */
+       s = (f-1)*f*(2*f-1)/6 ;
+       nms_lu += s ;
+
+       /* number of multiply-subtract pairs for LDL' */
+       nms_ldl += (s + lnzme)/2 ;
+
+       /* number of nz's in L (excl. diagonal) */
+       Info [AMD_LNZ] = lnz ;
+
+       /* number of divide ops for LU and LDL' */
+       Info [AMD_NDIV] = ndiv ;
+
+       /* number of multiply-subtract pairs for LDL' */
+       Info [AMD_NMULTSUBS_LDL] = nms_ldl ;
+
+       /* number of multiply-subtract pairs for LU */
+       Info [AMD_NMULTSUBS_LU] = nms_lu ;
+
+       /* number of "dense" rows/columns */
+       Info [AMD_NDENSE] = ndense ;
+
+       /* largest front is dmax-by-dmax */
+       Info [AMD_DMAX] = dmax ;
+
+       /* number of garbage collections in AMD */
+       Info [AMD_NCMPA] = ncmpa ;
+
+       /* successful ordering */
+       Info [AMD_STATUS] = AMD_OK ;
+    }
+
+/* -------------------------------------------------------------------------
+ * Variables at this point:
+ *
+ * Pe: holds the elimination tree.  The parent of j is FLIP (Pe [j]),
+ *     or EMPTY if j is a root.  The tree holds both elements and
+ *     non-principal (unordered) variables absorbed into them.
+ *     Dense variables are non-principal and unordered.
+ *
+ * Elen: holds the size of each element, including the diagonal part.
+ *     FLIP (Elen [e]) > 0 if e is an element.  For unordered
+ *     variables i, Elen [i] is EMPTY.
+ *
+ * Nv: Nv [e] > 0 is the number of pivots represented by the element e.
+ *     For unordered variables i, Nv [i] is zero.
+ *
+ * Contents no longer needed:
+ *     W, Iw, Len, Degree, Head, Next, Last.
+ *
+ * The matrix itself has been destroyed.
+ *
+ * n: the size of the matrix.
+ * No other scalars needed (pfree, iwlen, etc.)
+ * ------------------------------------------------------------------------- */
+
+    for (i = 0 ; i < n ; i++)
+    {
+       Pe [i] = FLIP (Pe [i]) ;
+       Elen [i] = FLIP (Elen [i]) ;
+    }
+
+/* Now the parent of j is Pe [j], or EMPTY if j is a root.  Elen [e] > 0
+ * is the size of element e.  Elen [i] is EMPTY for unordered variable i. */
+
+#ifndef NDEBUG
+    AMD_DEBUG2 (("\nTree:\n")) ;
+    for (i = 0 ; i < n ; i++)
+    {
+       AMD_DEBUG2 ((" "ID" parent: "ID"   ", i, Pe [i])) ;
+       ASSERT (Pe [i] >= EMPTY && Pe [i] < n) ;
+       if (Nv [i] > 0)
+       {
+           /* this is an element */
+           e = i ;
+           AMD_DEBUG2 ((" element, size is "ID"\n", Elen [i])) ;
+           ASSERT (Elen [e] > 0) ;
+       }
+       AMD_DEBUG2 (("\n")) ;
+    }
+    AMD_DEBUG2 (("\nelements:\n")) ;
+    for (e = 0 ; e < n ; e++)
+    {
+       if (Nv [e] > 0)
+       {
+           AMD_DEBUG3 (("Element e= "ID" size "ID" nv "ID" \n", e,
+               Elen [e], Nv [e])) ;
+       }
+    }
+    AMD_DEBUG2 (("\nvariables:\n")) ;
+    for (i = 0 ; i < n ; i++)
+    {
+       Int cnt ;
+       if (Nv [i] == 0)
+       {
+           AMD_DEBUG3 (("i unordered: "ID"\n", i)) ;
+           j = Pe [i] ;
+           cnt = 0 ;
+           AMD_DEBUG3 (("  j: "ID"\n", j)) ;
+           if (j == EMPTY)
+           {
+               AMD_DEBUG3 (("  i is a dense variable\n")) ;
+           }
+           else
+           {
+               ASSERT (j >= 0 && j < n) ;
+               while (Nv [j] == 0)
+               {
+                   AMD_DEBUG3 (("      j : "ID"\n", j)) ;
+                   j = Pe [j] ;
+                   AMD_DEBUG3 (("      j:: "ID"\n", j)) ;
+                   cnt++ ;
+                   if (cnt > n) break ;
+               }
+               e = j ;
+               AMD_DEBUG3 (("  got to e: "ID"\n", e)) ;
+           }
+       }
+    }
+#endif
+
+/* ========================================================================= */
+/* compress the paths of the variables */
+/* ========================================================================= */
+
+    for (i = 0 ; i < n ; i++)
+    {
+       if (Nv [i] == 0)
+       {
+
+           /* -------------------------------------------------------------
+            * i is an un-ordered row.  Traverse the tree from i until
+            * reaching an element, e.  The element, e, was the principal
+            * supervariable of i and all nodes in the path from i to when e
+            * was selected as pivot.
+            * ------------------------------------------------------------- */
+
+           AMD_DEBUG1 (("Path compression, i unordered: "ID"\n", i)) ;
+           j = Pe [i] ;
+           ASSERT (j >= EMPTY && j < n) ;
+           AMD_DEBUG3 (("      j: "ID"\n", j)) ;
+           if (j == EMPTY)
+           {
+               /* Skip a dense variable.  It has no parent. */
+               AMD_DEBUG3 (("      i is a dense variable\n")) ;
+               continue ;
+           }
+
+           /* while (j is a variable) */
+           while (Nv [j] == 0)
+           {
+               AMD_DEBUG3 (("          j : "ID"\n", j)) ;
+               j = Pe [j] ;
+               AMD_DEBUG3 (("          j:: "ID"\n", j)) ;
+               ASSERT (j >= 0 && j < n) ;
+           }
+           /* got to an element e */
+           e = j ;
+           AMD_DEBUG3 (("got to e: "ID"\n", e)) ;
+
+           /* -------------------------------------------------------------
+            * traverse the path again from i to e, and compress the path
+            * (all nodes point to e).  Path compression allows this code to
+            * compute in O(n) time.
+            * ------------------------------------------------------------- */
+
+           j = i ;
+           /* while (j is a variable) */
+           while (Nv [j] == 0)
+           {
+               jnext = Pe [j] ;
+               AMD_DEBUG3 (("j "ID" jnext "ID"\n", j, jnext)) ;
+               Pe [j] = e ;
+               j = jnext ;
+               ASSERT (j >= 0 && j < n) ;
+           }
+       }
+    }
+
+/* ========================================================================= */
+/* postorder the assembly tree */
+/* ========================================================================= */
+
+    AMD_postorder (n, Pe, Nv, Elen,
+       W,                      /* output order */
+       Head, Next, Last) ;     /* workspace */
+
+/* ========================================================================= */
+/* compute output permutation and inverse permutation */
+/* ========================================================================= */
+
+    /* W [e] = k means that element e is the kth element in the new
+     * order.  e is in the range 0 to n-1, and k is in the range 0 to
+     * the number of elements.  Use Head for inverse order. */
+
+    for (k = 0 ; k < n ; k++)
+    {
+       Head [k] = EMPTY ;
+       Next [k] = EMPTY ;
+    }
+    for (e = 0 ; e < n ; e++)
+    {
+       k = W [e] ;
+       ASSERT ((k == EMPTY) == (Nv [e] == 0)) ;
+       if (k != EMPTY)
+       {
+           ASSERT (k >= 0 && k < n) ;
+           Head [k] = e ;
+       }
+    }
+
+    /* construct output inverse permutation in Next,
+     * and permutation in Last */
+    nel = 0 ;
+    for (k = 0 ; k < n ; k++)
+    {
+       e = Head [k] ;
+       if (e == EMPTY) break ;
+       ASSERT (e >= 0 && e < n && Nv [e] > 0) ;
+       Next [e] = nel ;
+       nel += Nv [e] ;
+    }
+    ASSERT (nel == n - ndense) ;
+
+    /* order non-principal variables (dense, & 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/deal.II/contrib/umfpack/AMD/Source/amd_aat.c b/deal.II/contrib/umfpack/AMD/Source/amd_aat.c
new file mode 100644 (file)
index 0000000..3de1e24
--- /dev/null
@@ -0,0 +1,180 @@
+/* ========================================================================= */
+/* === AMD_aat ============================================================= */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,  */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README for License.         */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.           */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* AMD_aat:  compute the symmetry of the pattern of A, and count the number of
+ * nonzeros each column of A+A' (excluding the diagonal).  Assume the input
+ * matrix has no errors.
+ */
+
+#include "amd_internal.h"
+
+GLOBAL Int AMD_aat     /* returns nz in A+A' */
+(
+    Int n,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    Int Len [ ],       /* Len [j]: length of column j of A+A', excl diagonal*/
+    Int Tp [ ],                /* workspace of size n */
+    double Info [ ]
+) 
+{
+    Int p1, p2, p, i, j, pj, pj2, k, nzdiag, nzboth, nz, nzaat ;
+    double sym ;
+
+#ifndef NDEBUG
+    AMD_debug_init ("AMD AAT") ;
+    for (k = 0 ; k < n ; k++) Tp [k] = EMPTY ;
+    ASSERT (AMD_valid (n, n, Ap, Ai)) ;
+#endif
+
+    if (Info != (double *) NULL)
+    {
+       /* clear the Info array, if it exists */
+       for (i = 0 ; i < AMD_INFO ; i++)
+       {
+           Info [i] = EMPTY ;
+       }
+       Info [AMD_STATUS] = AMD_OK ;
+    }
+
+    for (k = 0 ; k < n ; k++)
+    {
+       Len [k] = 0 ;
+    }
+
+    nzdiag = 0 ;
+    nzboth = 0 ;
+    nz = Ap [n] ;
+
+    for (k = 0 ; k < n ; k++)
+    {
+       p1 = Ap [k] ;
+       p2 = Ap [k+1] ;
+       AMD_DEBUG2 (("\nAAT Column: "ID" p1: "ID" p2: "ID"\n", k, p1, p2)) ;
+
+       /* construct A+A' */
+       for (p = p1 ; p < p2 ; )
+       {
+           /* scan the upper triangular part of A */
+           j = Ai [p] ;
+           if (j < k)
+           {
+               /* entry A (j,k) is in the strictly upper triangular part,
+                * add both A (j,k) and A (k,j) to the matrix A+A' */
+               Len [j]++ ;
+               Len [k]++ ;
+               AMD_DEBUG3 (("    upper ("ID","ID") ("ID","ID")\n", j,k, k,j));
+               p++ ;
+           }
+           else if (j == k)
+           {
+               /* skip the diagonal */
+               p++ ;
+               nzdiag++ ;
+               break ;
+           }
+           else /* j > k */
+           {
+               /* first entry below the diagonal */
+               break ;
+           }
+           /* scan lower triangular part of A, in column j until reaching
+            * row k.  Start where last scan left off. */
+           ASSERT (Tp [j] != EMPTY) ;
+           ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ;
+           pj2 = Ap [j+1] ;
+           for (pj = Tp [j] ; pj < pj2 ; )
+           {
+               i = Ai [pj] ;
+               if (i < k)
+               {
+                   /* A (i,j) is only in the lower part, not in upper.
+                    * add both A (i,j) and A (j,i) to the matrix A+A' */
+                   Len [i]++ ;
+                   Len [j]++ ;
+                   AMD_DEBUG3 (("    lower ("ID","ID") ("ID","ID")\n",
+                       i,j, j,i)) ;
+                   pj++ ;
+               }
+               else if (i == k)
+               {
+                   /* entry A (k,j) in lower part and A (j,k) in upper */
+                   pj++ ;
+                   nzboth++ ;
+                   break ;
+               }
+               else /* i > k */
+               {
+                   /* consider this entry later, when k advances to i */
+                   break ;
+               }
+           }
+           Tp [j] = pj ;
+       }
+       /* Tp [k] points to the entry just below the diagonal in column k */
+       Tp [k] = p ;
+    }
+
+    /* clean up, for remaining mismatched entries */
+    for (j = 0 ; j < n ; j++)
+    {
+       for (pj = Tp [j] ; pj < Ap [j+1] ; pj++)
+       {
+           i = Ai [pj] ;
+           /* A (i,j) is only in the lower part, not in upper.
+            * add both A (i,j) and A (j,i) to the matrix A+A' */
+           Len [i]++ ;
+           Len [j]++ ;
+           AMD_DEBUG3 (("    lower cleanup ("ID","ID") ("ID","ID")\n",
+               i,j, j,i)) ;
+       }
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* compute the symmetry of the nonzero pattern of A */
+    /* --------------------------------------------------------------------- */
+
+    /* Given a matrix A, the symmetry of A is:
+     * B = tril (spones (A), -1) + triu (spones (A), 1) ;
+     *  sym = nnz (B & B') / nnz (B) ;
+     *  or 1 if nnz (B) is zero.
+     */
+
+    if (nz == nzdiag)
+    {
+       sym = 1 ;
+    }
+    else
+    {
+       sym = ((double) (2 * nzboth)) / ((double) (nz - nzdiag)) ;
+    }
+
+    nzaat = 0 ;
+    for (k = 0 ; k < n ; k++)
+    {
+       nzaat += Len [k] ;
+    }
+    AMD_DEBUG1 (("AMD nz in A+A', excluding diagonal (nzaat) = "ID"\n",nzaat));
+    AMD_DEBUG1 (("   nzboth: "ID" nz: "ID" nzdiag: "ID" symmetry: %g\n",
+               nzboth, nz, nzdiag, sym)) ;
+
+    if (Info != (double *) NULL)
+    {
+       Info [AMD_STATUS] = AMD_OK ;
+       Info [AMD_N] = n ;
+       Info [AMD_NZ] = nz ;
+       Info [AMD_SYMMETRY] = sym ;         /* symmetry of pattern of A */
+       Info [AMD_NZDIAG] = nzdiag ;        /* nonzeros on diagonal of A */
+       Info [AMD_NZ_A_PLUS_AT] = nzaat ;   /* nonzeros in A+A' */
+    }
+
+    return (nzaat) ;
+}
diff --git a/deal.II/contrib/umfpack/AMD/Source/amd_control.c b/deal.II/contrib/umfpack/AMD/Source/amd_control.c
new file mode 100644 (file)
index 0000000..6fc8f9f
--- /dev/null
@@ -0,0 +1,61 @@
+/* ========================================================================= */
+/* === AMD_control ========================================================= */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,  */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README for License.         */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.           */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* User-callable.  Prints the control parameters for AMD.  See amd.h
+ * for details.  If the Control array is not present, the defaults are
+ * printed instead.
+ */
+
+#include "amd_internal.h"
+
+GLOBAL void AMD_control
+(
+    double Control [ ]
+)
+{
+    double alpha ;
+    Int aggressive ;
+
+    if (Control != (double *) NULL)
+    {
+       alpha = Control [AMD_DENSE] ;
+       aggressive = Control [AMD_AGGRESSIVE] != 0 ;
+    }
+    else
+    {
+       alpha = AMD_DEFAULT_DENSE ;
+       aggressive = AMD_DEFAULT_AGGRESSIVE ;
+    }
+
+    PRINTF (("\namd:  approximate minimum degree ordering, parameters:\n"
+       "    dense row parameter: %g\n", alpha)) ;
+
+    if (alpha < 0)
+    {
+       PRINTF (("    no rows treated as dense\n")) ;
+    }
+    else
+    {
+       PRINTF ((
+       "    (rows with more than max (%g * sqrt (n), 16) entries are\n"
+       "    considered \"dense\", and placed last in output permutation)\n",
+       alpha)) ;
+    }
+
+    if (aggressive)
+    {
+       PRINTF (("    aggressive absorption:  yes\n\n")) ;
+    }
+    else
+    {
+       PRINTF (("    aggressive absorption:  no\n\n")) ;
+    }
+}
diff --git a/deal.II/contrib/umfpack/AMD/Source/amd_defaults.c b/deal.II/contrib/umfpack/AMD/Source/amd_defaults.c
new file mode 100644 (file)
index 0000000..d0737f4
--- /dev/null
@@ -0,0 +1,33 @@
+/* ========================================================================= */
+/* === AMD_defaults ======================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,  */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README for License.         */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.           */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* User-callable.  Sets default control parameters for AMD.  See amd.h
+ * for details.
+ */
+
+#include "amd_internal.h"
+
+GLOBAL void AMD_defaults
+(
+    double Control [ ]
+)
+{
+    Int i ;
+    if (Control != (double *) NULL)
+    {
+       for (i = 0 ; i < AMD_CONTROL ; i++)
+       {
+           Control [i] = 0 ;
+       }
+       Control [AMD_DENSE] = AMD_DEFAULT_DENSE ;
+       Control [AMD_AGGRESSIVE] = AMD_DEFAULT_AGGRESSIVE ;
+    }
+}
diff --git a/deal.II/contrib/umfpack/AMD/Source/amd_dump.c b/deal.II/contrib/umfpack/AMD/Source/amd_dump.c
new file mode 100644 (file)
index 0000000..c526007
--- /dev/null
@@ -0,0 +1,176 @@
+/* ========================================================================= */
+/* === AMD_dump ============================================================ */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,  */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README for License.         */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.           */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* Debugging routines for AMD.  Not used if NDEBUG is not defined at compile-
+ * time (the default).  See comments in amd_internal.h on how to enable
+ * debugging.  Not user-callable.
+ */
+
+#include "amd_internal.h"
+
+#ifndef NDEBUG
+
+/* This global variable is present only when debugging */
+GLOBAL Int AMD_debug = -999 ;          /* default is no debug printing */
+
+/* ========================================================================= */
+/* === AMD_debug_init ====================================================== */
+/* ========================================================================= */
+
+/* Sets the debug print level, by reading the file debug.amd (if it exists) */
+
+GLOBAL void AMD_debug_init ( char *s )
+{
+    FILE *f ;
+    f = fopen ("debug.amd", "r") ;
+    if (f == (FILE *) NULL)
+    {
+       AMD_debug = -999 ;
+    }
+    else
+    {
+       fscanf (f, ID, &AMD_debug) ;
+       fclose (f) ;
+    }
+    if (AMD_debug >= 0) printf ("%s: AMD_debug_init, D= "ID"\n", s, AMD_debug);
+}
+
+/* ========================================================================= */
+/* === AMD_dump ============================================================ */
+/* ========================================================================= */
+
+/* Dump AMD's data structure, except for the hash buckets.  This routine
+ * cannot be called when the hash buckets are non-empty.
+ */
+
+GLOBAL void AMD_dump (
+    Int n,         /* A is n-by-n */
+    Int Pe [ ],            /* pe [0..n-1]: index in iw of start of row i */
+    Int Iw [ ],            /* workspace of size iwlen, iwlen [0..pfree-1]
+                    * holds the matrix on input */
+    Int Len [ ],    /* len [0..n-1]: length for row i */
+    Int iwlen,     /* length of iw */
+    Int pfree,     /* iw [pfree ... iwlen-1] is empty on input */
+    Int Nv [ ],            /* nv [0..n-1] */
+    Int Next [ ],   /* next [0..n-1] */
+    Int Last [ ],   /* last [0..n-1] */
+    Int Head [ ],   /* head [0..n-1] */
+    Int Elen [ ],   /* size n */
+    Int Degree [ ], /* size n */
+    Int W [ ],     /* size n */
+    Int nel
+)
+{
+    Int i, pe, elen, nv, len, e, p, k, j, deg, w, cnt, ilast ;
+
+    if (AMD_debug < 0) return ;
+    ASSERT (pfree <= iwlen) ;
+    for (i = 0 ; i < n ; i++)
+    {
+       pe = Pe [i] ;
+       elen = Elen [i] ;
+       nv = Nv [i] ;
+       len = Len [i] ;
+       w = W [i] ;
+
+       if (elen >= EMPTY)
+       {
+           if (nv == 0)
+           {
+               AMD_DEBUG3 (("\nI "ID": nonprincipal:    ", i)) ;
+               ASSERT (elen == EMPTY) ;
+               if (pe == EMPTY)
+               {
+                   AMD_DEBUG3 ((" dense node\n")) ;
+                   ASSERT (w == 1) ;
+               }
+               else
+               {
+                   ASSERT (pe < EMPTY) ;
+                   AMD_DEBUG3 ((" i "ID" -> parent "ID"\n", i, FLIP (Pe[i])));
+               }
+           }
+           else
+           {
+               AMD_DEBUG3 (("\nI "ID": active principal supervariable:\n",i));
+               AMD_DEBUG3 (("   nv(i): "ID"  Flag: %d\n", nv, (nv < 0))) ;
+               ASSERT (elen >= 0) ;
+               ASSERT (nv > 0 && pe >= 0) ;
+               p = pe ;
+               AMD_DEBUG3 (("   e/s: ")) ;
+               if (elen == 0) AMD_DEBUG3 ((" : ")) ;
+               ASSERT (pe < pfree) ;
+               for (k = 0 ; k < len ; k++)
+               {
+                   j = Iw [p] ;
+                   AMD_DEBUG3 (("  "ID"", j)) ;
+                   ASSERT (j >= 0 && j < n) ;
+                   if (k == elen-1) AMD_DEBUG3 ((" : ")) ;
+                   p++ ;
+               }
+               AMD_DEBUG3 (("\n")) ;
+           }
+       }
+       else
+       {
+           e = i ;
+           if (w == 0)
+           {
+               AMD_DEBUG3 (("\nE "ID": absorbed element: w "ID"\n", e, w)) ;
+               ASSERT (nv > 0 && pe < 0) ;
+               AMD_DEBUG3 ((" e "ID" -> parent "ID"\n", e, FLIP (Pe [e]))) ;
+           }
+           else
+           {
+               AMD_DEBUG3 (("\nE "ID": unabsorbed element: w "ID"\n", e, w)) ;
+               ASSERT (nv > 0 && pe >= 0) ;
+               p = pe ;
+               AMD_DEBUG3 ((" : ")) ;
+               ASSERT (pe < pfree) ;
+               for (k = 0 ; k < len ; k++)
+               {
+                   j = Iw [p] ;
+                   AMD_DEBUG3 (("  "ID"", j)) ;
+                   ASSERT (j >= 0 && j < n) ;
+                   p++ ;
+               }
+               AMD_DEBUG3 (("\n")) ;
+           }
+       }
+    }
+
+    /* this routine cannot be called when the hash buckets are non-empty */
+    AMD_DEBUG3 (("\nDegree lists:\n")) ;
+    if (nel >= 0)
+    {
+       cnt = 0 ;
+       for (deg = 0 ; deg < n ; deg++)
+       {
+           if (Head [deg] == EMPTY) continue ;
+           ilast = EMPTY ;
+           AMD_DEBUG3 ((ID": ", deg)) ;
+           for (i = Head [deg] ; i != EMPTY ; i = Next [i])
+           {
+               AMD_DEBUG3 ((" "ID" : next "ID" last "ID" deg "ID"\n",
+                   i, Next [i], Last [i], Degree [i])) ;
+               ASSERT (i >= 0 && i < n && ilast == Last [i] &&
+                   deg == Degree [i]) ;
+               cnt += Nv [i] ;
+               ilast = i ;
+           }
+           AMD_DEBUG3 (("\n")) ;
+       }
+       ASSERT (cnt == n - nel) ;
+    }
+
+}
+
+#endif
diff --git a/deal.II/contrib/umfpack/AMD/Source/amd_info.c b/deal.II/contrib/umfpack/AMD/Source/amd_info.c
new file mode 100644 (file)
index 0000000..1cc8968
--- /dev/null
@@ -0,0 +1,115 @@
+/* ========================================================================= */
+/* === AMD_info ============================================================ */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,  */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README for License.         */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.           */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* User-callable.  Prints the output statistics for AMD.  See amd.h
+ * for details.  If the Info array is not present, nothing is printed.
+ */
+
+#include "amd_internal.h"
+
+#define PRI(format,x) { if (x >= 0) { PRINTF ((format, x)) ; }}
+
+GLOBAL void AMD_info
+(
+    double Info [ ]
+)
+{
+    double n, ndiv, nmultsubs_ldl, nmultsubs_lu, lnz, lnzd ;
+
+    if (!Info)
+    {
+       return ;
+    }
+
+    n = Info [AMD_N] ;
+    ndiv = Info [AMD_NDIV] ;
+    nmultsubs_ldl = Info [AMD_NMULTSUBS_LDL] ;
+    nmultsubs_lu = Info [AMD_NMULTSUBS_LU] ;
+    lnz = Info [AMD_LNZ] ;
+    lnzd = (n >= 0 && lnz >= 0) ? (n + lnz) : (-1) ;
+
+    /* AMD return status */
+    PRINTF ((
+       "\namd:  approximate minimum degree ordering, results:\n"
+       "    status: ")) ;
+    if (Info [AMD_STATUS] == AMD_OK)
+    {
+       PRINTF (("OK\n")) ;
+    }
+    else if (Info [AMD_STATUS] == AMD_OUT_OF_MEMORY)
+    {
+       PRINTF (("out of memory\n")) ;
+    }
+    else if (Info [AMD_STATUS] == AMD_INVALID)
+    {
+       PRINTF (("invalid matrix\n")) ;
+    }
+    else
+    {
+       PRINTF (("unknown\n")) ;
+    }
+
+    /* statistics about the input matrix */
+    PRI ("    n, dimension of A:                                  %.20g\n", n);
+    PRI ("    nz, number of nonzeros in A:                        %.20g\n",
+       Info [AMD_NZ]) ;
+    PRI ("    symmetry of A:                                      %.4f\n",
+       Info [AMD_SYMMETRY]) ;
+    PRI ("    number of nonzeros on diagonal:                     %.20g\n",
+       Info [AMD_NZDIAG]) ;
+    PRI ("    nonzeros in pattern of A+A' (excl. diagonal):       %.20g\n",
+       Info [AMD_NZ_A_PLUS_AT]) ;
+    PRI ("    # dense rows/columns of A+A':                       %.20g\n",
+       Info [AMD_NDENSE]) ;
+
+    /* statistics about AMD's behavior  */
+    PRI ("    memory used, in bytes:                              %.20g\n",
+       Info [AMD_MEMORY]) ;
+    PRI ("    # of memory compactions:                            %.20g\n",
+       Info [AMD_NCMPA]) ;
+
+    /* statistics about the ordering quality */
+    PRINTF (("\n"
+       "    The following approximate statistics are for a subsequent\n"
+       "    factorization of A(P,P) + A(P,P)'.  They are slight upper\n"
+       "    bounds if there are no dense rows/columns in A+A', and become\n"
+       "    looser if dense rows/columns exist.\n\n")) ;
+
+    PRI ("    nonzeros in L (excluding diagonal):                 %.20g\n",
+       lnz) ;
+    PRI ("    nonzeros in L (including diagonal):                 %.20g\n",
+       lnzd) ;
+    PRI ("    # divide operations for LDL' or LU:                 %.20g\n",
+       ndiv) ;
+    PRI ("    # multiply-subtract operations for LDL':            %.20g\n",
+       nmultsubs_ldl) ;
+    PRI ("    # multiply-subtract operations for LU:              %.20g\n",
+       nmultsubs_lu) ;
+    PRI ("    max nz. in any column of L (incl. diagonal):        %.20g\n",
+       Info [AMD_DMAX]) ;
+
+    /* total flop counts for various factorizations */
+
+    if (n >= 0 && ndiv >= 0 && nmultsubs_ldl >= 0 && nmultsubs_lu >= 0)
+    {
+       PRINTF (("\n"
+       "    chol flop count for real A, sqrt counted as 1 flop: %.20g\n"
+       "    LDL' flop count for real A:                         %.20g\n"
+       "    LDL' flop count for complex A:                      %.20g\n"
+       "    LU flop count for real A (with no pivoting):        %.20g\n"
+       "    LU flop count for complex A (with no pivoting):     %.20g\n\n",
+       n + ndiv + 2*nmultsubs_ldl,
+           ndiv + 2*nmultsubs_ldl,
+         9*ndiv + 8*nmultsubs_ldl,
+           ndiv + 2*nmultsubs_lu,
+         9*ndiv + 8*nmultsubs_lu)) ;
+    }
+}
diff --git a/deal.II/contrib/umfpack/AMD/Source/amd_internal.h b/deal.II/contrib/umfpack/AMD/Source/amd_internal.h
new file mode 100644 (file)
index 0000000..e1ec500
--- /dev/null
@@ -0,0 +1,426 @@
+/* ========================================================================= */
+/* === amd_internal.h ====================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,  */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README for License.         */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.           */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* This file is for internal use in AMD itself, and does not normally need to
+ * be included in user code.  Use amd.h instead.
+ *
+ * The following compile-time definitions affect how AMD is compiled.
+ *
+ *     -DMATLAB_MEX_FILE
+ *
+ *         This flag is turned on when compiling the amd mexFunction for
+ *         use in MATLAB.
+ *
+ *     -DMATHWORKS
+ *
+ *         This flag is turned on when compiling amd as a built-in routine
+ *         in MATLAB.  Internal routines utMalloc, utFree, utRealloc, and
+ *         utPrintf are used, and the MathWorks "util.h" file is included.  
+ *         This option is intended for use by The MathWorks, Inc., only.
+ *
+ *     -DNDEBUG
+ *
+ *         Debugging mode (if NDEBUG is not defined).  The default, of course,
+ *         is no debugging.  Turning on debugging takes some work (see below).
+ *         If you do not edit this file, then debugging is turned off anyway,
+ *         regardless of whether or not -DNDEBUG is specified in your compiler
+ *         options.
+ *
+ *     -DALLOCATE=allocation_routine
+ *     -DFREE=free_routine
+ *
+ *         If you do not wish to use malloc or free, you can define the
+ *         routines to be used here.  You must specify both of them, or
+ *         neither.
+ *
+ *     -DPRINTF=printf_routine
+ *
+ *         If you wish to use a routine other than printf, you can define it
+ *         with -DPRINTF= followed by the name of the printf replacement.
+ */
+
+/* ========================================================================= */
+/* === NDEBUG ============================================================== */
+/* ========================================================================= */
+
+/*
+    AMD will be exceedingly slow when running in debug mode.  The next three
+    lines ensure that debugging is turned off.
+*/
+#ifndef NDEBUG
+#define NDEBUG
+#endif
+
+/*
+    To enable debugging, uncomment the following line:
+#undef NDEBUG
+*/
+
+/* ------------------------------------------------------------------------- */
+/* ANSI include files */
+/* ------------------------------------------------------------------------- */
+
+/* from stdlib.h:  malloc, free, realloc (when not compiling for MATLAB) */
+#include <stdlib.h>
+
+/* from stdio.h:  printf.  When in debug mode:  fopen, fscanf */
+#include <stdio.h>
+
+/* 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 MATHWORKS
+#include "util.h"
+#endif
+
+#ifdef MATLAB_MEX_FILE
+#include "matrix.h"
+#include "mex.h"
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* basic definitions */
+/* ------------------------------------------------------------------------- */
+
+#ifdef FLIP
+#undef FLIP
+#endif
+
+#ifdef MAX
+#undef MAX
+#endif
+
+#ifdef MIN
+#undef MIN
+#endif
+
+#ifdef EMPTY
+#undef EMPTY
+#endif
+
+#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
+
+/* ------------------------------------------------------------------------- */
+/* integer type for AMD: int or long */
+/* ------------------------------------------------------------------------- */
+
+#if defined (DLONG) || defined (ZLONG)
+
+#define Int long
+#define ID "%ld"
+#define Int_MAX LONG_MAX
+#define Int_MIN LONG_MIN
+
+#define AMD_order amd_l_order
+#define AMD_defaults amd_l_defaults
+#define AMD_control amd_l_control
+#define AMD_info amd_l_info
+#define AMD_1 amd_l1
+#define AMD_2 amd_l2
+#define AMD_valid amd_l_valid
+#define AMD_aat amd_l_aat
+#define AMD_postorder amd_l_postorder
+#define AMD_post_tree amd_l_post_tree
+#define AMD_dump amd_l_dump
+#define AMD_debug amd_l_debug
+#define AMD_debug_init amd_l_debug_init
+#define AMD_wpreprocess amd_l_wpreprocess
+#define AMD_preprocess amd_l_preprocess
+#define AMD_preprocess_valid amd_l_preprocess_valid
+
+#else
+
+#define Int int
+#define ID "%d"
+#define Int_MAX INT_MAX
+#define Int_MIN INT_MIN
+
+#define AMD_order amd_order
+#define AMD_defaults amd_defaults
+#define AMD_control amd_control
+#define AMD_info amd_info
+#define AMD_1 amd_1
+#define AMD_2 amd_2
+#define AMD_valid amd_valid
+#define AMD_aat amd_aat
+#define AMD_postorder amd_postorder
+#define AMD_post_tree amd_post_tree
+#define AMD_dump amd_dump
+#define AMD_debug amd_debug
+#define AMD_debug_init amd_debug_init
+#define AMD_wpreprocess amd_wpreprocess
+#define AMD_preprocess amd_preprocess
+#define AMD_preprocess_valid amd_preprocess_valid
+
+#endif
+
+/* ========================================================================= */
+/* === Memory allocator ==================================================== */
+/* ========================================================================= */
+
+/* The MATLAB mexFunction uses MATLAB's memory manager, while the C-callable */
+/* AMD routine uses the ANSI C malloc, free, and realloc routines. */
+
+#ifndef ALLOCATE
+#ifdef MATLAB_MEX_FILE
+#define ALLOCATE mxMalloc
+#define FREE mxFree
+#else
+#ifdef MATHWORKS
+/* Compiling as a built-in routine.  Since out-of-memory conditions are checked
+ * after every allocation, we can use ut* routines here. */
+#define ALLOCATE utMalloc
+#define FREE utFree
+#else
+/* use the ANSI C memory allocation routines */
+#define ALLOCATE malloc
+#define FREE free
+#endif
+#endif
+#endif
+
+
+/* ========================================================================= */
+/* === PRINTF macro ======================================================== */
+/* ========================================================================= */
+
+/* All output goes through the PRINTF macro.  */
+
+#ifndef PRINTF
+#ifdef MATLAB_MEX_FILE
+#define PRINTF(params) { (void) mexPrintf params ; }
+#else
+#ifdef MATHWORKS
+#define PRINTF(params) { (void) utPrintf params ; }
+#else
+#define PRINTF(params) { (void) printf params ; }
+#endif
+#endif
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* AMD routine definitions (user-callable) */
+/* ------------------------------------------------------------------------- */
+
+#include "amd.h"
+
+/* ------------------------------------------------------------------------- */
+/* AMD routine definitions (not user-callable) */
+/* ------------------------------------------------------------------------- */
+
+GLOBAL Int AMD_valid
+(
+    Int n_row,
+    Int n_col,
+    const Int Ap [ ],
+    const Int Ai [ ]
+) ;
+
+GLOBAL Int AMD_aat
+(
+    Int n,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    Int Len [ ],
+    Int Tp [ ],        
+    double Info [ ]
+) ;
+
+GLOBAL void AMD_1
+(
+    Int n,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    Int P [ ],
+    Int Pinv [ ],
+    Int Len [ ],
+    Int slen,
+    Int S [ ],
+    double Control [ ],
+    double Info [ ]
+) ;
+
+GLOBAL void AMD_2 (
+    Int n,
+    Int Pe [ ],
+    Int Iw [ ],
+    Int Len [ ],
+    Int iwlen,
+    Int pfree,
+    Int Nv [ ],
+    Int Next [ ], 
+    Int Last [ ],
+    Int Head [ ],
+    Int Elen [ ],
+    Int Degree [ ],
+    Int W [ ],
+    double Control [ ],
+    double Info [ ]
+) ;
+
+GLOBAL void AMD_postorder
+(
+    Int nn,
+    Int Parent [ ],
+    Int Npiv [ ],
+    Int Fsize [ ],
+    Int Order [ ],
+    Int Child [ ],
+    Int Sibling [ ],
+    Int Stack [ ]
+) ;
+
+GLOBAL Int AMD_post_tree
+(
+    Int root,
+    Int k,
+    Int Child [ ],
+    const Int Sibling [ ],
+    Int Order [ ],
+    Int Stack [ ]
+#ifndef NDEBUG
+    , Int nn
+#endif
+) ;
+
+GLOBAL void AMD_wpreprocess
+(
+    Int n,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    Int Rp [ ],
+    Int Ri [ ],
+    Int W [ ],
+    Int Flag [ ]
+) ;
+
+GLOBAL Int AMD_preprocess_valid
+(
+    Int n,
+    const Int Ap [ ],
+    const Int Ai [ ]
+) ;
+
+/* ------------------------------------------------------------------------- */
+/* debugging definitions */
+/* ------------------------------------------------------------------------- */
+
+/* from assert.h:  assert macro */
+#if !defined (MATHWORKS) && !defined (MATLAB_MEX_FILE)
+#include <assert.h>
+#endif
+
+#ifndef NDEBUG
+
+GLOBAL Int AMD_debug ;
+
+GLOBAL void AMD_debug_init ( char *s ) ;
+
+GLOBAL void AMD_dump (
+    Int n,
+    Int Pe [ ],
+    Int Iw [ ],
+    Int Len [ ],
+    Int iwlen,
+    Int pfree,
+    Int Nv [ ],
+    Int Next [ ],
+    Int Last [ ],
+    Int Head [ ],
+    Int Elen [ ],
+    Int Degree [ ],
+    Int W [ ],
+    Int nel
+) ;
+
+#ifdef ASSERT
+#undef ASSERT
+#endif
+
+#ifdef MATLAB_MEX_FILE
+#define ASSERT(expression) (mxAssert ((expression), ""))
+#else
+#ifdef MATHWORKS
+#define ASSERT(expression) (utAssert (expression))
+#else
+#define ASSERT(expression) (assert (expression))
+#endif
+#endif /* MATLAB_MEX_FILE */
+
+#define AMD_DEBUG0(params) { PRINTF (params) ; }
+#define AMD_DEBUG1(params) { if (AMD_debug >= 1) PRINTF (params) ; }
+#define AMD_DEBUG2(params) { if (AMD_debug >= 2) PRINTF (params) ; }
+#define AMD_DEBUG3(params) { if (AMD_debug >= 3) PRINTF (params) ; }
+#define AMD_DEBUG4(params) { if (AMD_debug >= 4) PRINTF (params) ; }
+
+#else
+
+#define AMD_DEBUG0(params)
+#define AMD_DEBUG1(params)
+#define AMD_DEBUG2(params)
+#define AMD_DEBUG3(params)
+#define AMD_DEBUG4(params)
+
+#define ASSERT(expression)
+
+#endif
diff --git a/deal.II/contrib/umfpack/AMD/Source/amd_order.c b/deal.II/contrib/umfpack/AMD/Source/amd_order.c
new file mode 100644 (file)
index 0000000..eac5471
--- /dev/null
@@ -0,0 +1,139 @@
+/* ========================================================================= */
+/* === AMD_order =========================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,  */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README for License.         */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.           */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* User-callable AMD minimum degree ordering routine.  See amd.h for
+ * documentation.
+ */
+
+#include "amd_internal.h"
+
+GLOBAL Int AMD_order
+(
+    Int n,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    Int P [ ],
+    double Control [ ],
+    double Info [ ]
+)
+{
+    Int slen, *Len, *S, nz, nzaat, i, *Pinv, info ;
+
+#ifndef NDEBUG
+    AMD_debug_init ("amd") ;
+#endif
+
+    /* clear the Info array, if it exists */
+    info = Info != (double *) NULL ;
+    if (info)
+    {
+       for (i = 0 ; i < AMD_INFO ; i++)
+       {
+           Info [i] = EMPTY ;
+       }
+       Info [AMD_N] = n ;
+       Info [AMD_STATUS] = AMD_OK ;
+    }
+
+    /* make sure inputs exist and n is >= 0 */
+    if (Ai == (Int *) NULL || Ap == (Int *) NULL || P == (Int *) NULL || n < 0)
+    {
+       if (info) Info [AMD_STATUS] = AMD_INVALID ;
+       return (AMD_INVALID) ;      /* arguments are invalid */
+    }
+
+    if (n == 0)
+    {
+       return (AMD_OK) ;           /* n is 0 so there's nothing to do */
+    }
+
+    nz = Ap [n] ;
+    if (info)
+    {
+       Info [AMD_NZ] = nz ;
+    }
+    if (nz < 0)
+    {
+       if (info) Info [AMD_STATUS] = AMD_INVALID ;
+       return (AMD_INVALID) ;
+    }
+
+    /* Avoid integer overflow in memory size calculations.  The space required
+     * by AMD is at most 2.4nz + 8n for S, and n for Len.
+     * Note nz - n <= nzaat <= 2*nz, below. */
+    if ((2.4 * (double) nz + 8 * (double) n) > (double) Int_MAX / sizeof (Int))
+    {
+       /* :: int overflow :: */
+       if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
+       return (AMD_OUT_OF_MEMORY) ;
+    }
+
+    if (!AMD_valid (n, n, Ap, Ai))
+    {
+       if (info) Info [AMD_STATUS] = AMD_INVALID ;
+       return (AMD_INVALID) ;      /* matrix is invalid */
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* determine the symmetry and count off-diagonal nonzeros in A+A' */
+    /* --------------------------------------------------------------------- */
+
+    /* allocate size-n integer workspace */
+    Len = (Int *) ALLOCATE (n * sizeof (Int)) ;
+    if (!Len)
+    {
+       /* :: out of memory :: */
+       if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
+       return (AMD_OUT_OF_MEMORY) ;
+    }
+    nzaat = AMD_aat (n, Ap, Ai, Len, P, Info) ;
+    AMD_DEBUG1 (("nzaat: "ID"\n", nzaat)) ;
+    ASSERT (nz-n <= nzaat && nzaat <= 2*nz) ;
+
+    /* --------------------------------------------------------------------- */
+    /* allocate workspace for matrix, elbow room, and 7 size-n vectors */
+    /* --------------------------------------------------------------------- */
+
+    slen = (nzaat + nzaat/5 + n) + 7*n ;
+    if (info)
+    {
+       /* memory usage (Len and S), in bytes. */
+       Info [AMD_MEMORY] = ((double) slen + n) * sizeof (Int) ;
+    }
+    S = (Int *) ALLOCATE (slen * sizeof (Int)) ;
+    AMD_DEBUG1 ((" S "ID" Len "ID" n "ID" nzaat "ID" slen "ID"\n",
+       (Int) S, (Int) Len, n, nzaat, slen)) ;
+    if (S == (Int *) NULL)
+    {
+       /* :: out of memory :: */
+       FREE (Len) ;
+       if (Info != (double *) NULL) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
+       return (AMD_OUT_OF_MEMORY) ;
+    }
+
+    /* allocate space from S for Pinv */
+    Pinv = S + slen - n ;
+    slen -= n ;
+
+    /* --------------------------------------------------------------------- */
+    /* order the matrix */
+    /* --------------------------------------------------------------------- */
+
+    AMD_1 (n, Ap, Ai, P, Pinv, Len, slen, S, Control, Info) ;
+
+    /* --------------------------------------------------------------------- */
+    /* free the workspace */
+    /* --------------------------------------------------------------------- */
+
+    FREE (Len) ;
+    FREE (S) ;
+    return (AMD_OK) ;      /* successful ordering */
+}
diff --git a/deal.II/contrib/umfpack/AMD/Source/amd_post_tree.c b/deal.II/contrib/umfpack/AMD/Source/amd_post_tree.c
new file mode 100644 (file)
index 0000000..3928925
--- /dev/null
@@ -0,0 +1,121 @@
+/* ========================================================================= */
+/* === AMD_post_tree ======================================================= */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,  */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README for License.         */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.           */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* Post-ordering of a supernodal elimination tree.  */
+
+#include "amd_internal.h"
+
+GLOBAL Int AMD_post_tree
+(
+    Int root,                  /* root of the tree */
+    Int k,                     /* start numbering at k */
+    Int Child [ ],             /* input argument of size nn, undefined on
+                                * output.  Child [i] is the head of a link
+                                * list of all nodes that are children of node
+                                * i in the tree. */
+    const Int Sibling [ ],     /* input argument of size nn, not modified.
+                                * If f is a node in the link list of the
+                                * children of node i, then Sibling [f] is the
+                                * next child of node i.
+                                */
+    Int Order [ ],             /* output order, of size nn.  Order [i] = k
+                                * if node i is the kth node of the reordered
+                                * tree. */
+    Int Stack [ ]              /* workspace of size nn */
+#ifndef NDEBUG
+    , Int nn                   /* nodes are in the range 0..nn-1. */
+#endif
+)
+{
+    Int f, head, h, i ;
+
+#if 0
+    /* --------------------------------------------------------------------- */
+    /* recursive version (Stack [ ] is not used): */
+    /* --------------------------------------------------------------------- */
+
+    /* this is simple, but can caouse stack overflow if nn is large */
+    i = root ;
+    for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+    {
+       k = AMD_post_tree (f, k, Child, Sibling, Order, Stack, nn) ;
+    }
+    Order [i] = k++ ;
+    return (k) ;
+#endif
+
+    /* --------------------------------------------------------------------- */
+    /* non-recursive version, using an explicit stack */
+    /* --------------------------------------------------------------------- */
+
+    /* push root on the stack */
+    head = 0 ;
+    Stack [0] = root ;
+
+    while (head >= 0)
+    {
+       /* get head of stack */
+       ASSERT (head < nn) ;
+       i = Stack [head] ;
+       AMD_DEBUG1 (("head of stack "ID" \n", i)) ;
+       ASSERT (i >= 0 && i < nn) ;
+
+       if (Child [i] != EMPTY)
+       {
+           /* the children of i are not yet ordered */
+           /* push each child onto the stack in reverse order */
+           /* so that small ones at the head of the list get popped first */
+           /* and the biggest one at the end of the list gets popped last */
+           for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+           {
+               head++ ;
+               ASSERT (head < nn) ;
+               ASSERT (f >= 0 && f < nn) ;
+           }
+           h = head ;
+           ASSERT (head < nn) ;
+           for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+           {
+               ASSERT (h > 0) ;
+               Stack [h--] = f ;
+               AMD_DEBUG1 (("push "ID" on stack\n", f)) ;
+               ASSERT (f >= 0 && f < nn) ;
+           }
+           ASSERT (Stack [h] == i) ;
+
+           /* delete child list so that i gets ordered next time we see it */
+           Child [i] = EMPTY ;
+       }
+       else
+       {
+           /* the children of i (if there were any) are already ordered */
+           /* remove i from the stack and order it.  Front i is kth front */
+           head-- ;
+           AMD_DEBUG1 (("pop "ID" order "ID"\n", i, k)) ;
+           Order [i] = k++ ;
+           ASSERT (k <= nn) ;
+       }
+
+#ifndef NDEBUG
+       AMD_DEBUG1 (("\nStack:")) ;
+       for (h = head ; h >= 0 ; h--)
+       {
+           Int j = Stack [h] ;
+           AMD_DEBUG1 ((" "ID, j)) ;
+           ASSERT (j >= 0 && j < nn) ;
+       }
+       AMD_DEBUG1 (("\n\n")) ;
+       ASSERT (head < nn) ;
+#endif
+
+    }
+    return (k) ;
+}
diff --git a/deal.II/contrib/umfpack/AMD/Source/amd_postorder.c b/deal.II/contrib/umfpack/AMD/Source/amd_postorder.c
new file mode 100644 (file)
index 0000000..2b1bcd6
--- /dev/null
@@ -0,0 +1,207 @@
+/* ========================================================================= */
+/* === AMD_postorder ======================================================= */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,  */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README for License.         */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.           */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* Perform a postordering (via depth-first search) of an assembly tree. */
+
+#include "amd_internal.h"
+
+GLOBAL void AMD_postorder
+(
+    /* inputs, not modified on output: */
+    Int nn,            /* nodes are in the range 0..nn-1 */
+    Int Parent [ ],    /* Parent [j] is the parent of j, or EMPTY if root */
+    Int Nv [ ],                /* Nv [j] > 0 number of pivots represented by node j,
+                        * or zero if j is not a node. */
+    Int Fsize [ ],     /* Fsize [j]: size of node j */
+
+    /* output, not defined on input: */
+    Int Order [ ],     /* output post-order */
+
+    /* workspaces of size nn: */
+    Int Child [ ],
+    Int Sibling [ ],
+    Int Stack [ ]
+)
+{
+    Int i, j, k, parent, frsize, f, fprev, maxfrsize, bigfprev, bigf, fnext ;
+
+    for (j = 0 ; j < nn ; j++)
+    {
+       Child [j] = EMPTY ;
+       Sibling [j] = EMPTY ;
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* place the children in link lists - bigger elements tend to be last */
+    /* --------------------------------------------------------------------- */
+
+    for (j = nn-1 ; j >= 0 ; j--)
+    {
+       if (Nv [j] > 0)
+       {
+           /* this is an element */
+           parent = Parent [j] ;
+           if (parent != EMPTY)
+           {
+               /* place the element in link list of the children its parent */
+               /* bigger elements will tend to be at the end of the list */
+               Sibling [j] = Child [parent] ;
+               Child [parent] = j ;
+           }
+       }
+    }
+
+#ifndef NDEBUG
+    {
+       Int nels, ff, nchild ;
+       AMD_DEBUG1 (("\n\n================================ AMD_postorder:\n"));
+       nels = 0 ;
+       for (j = 0 ; j < nn ; j++)
+       {
+           if (Nv [j] > 0)
+           {
+               AMD_DEBUG1 (( ""ID" :  nels "ID" npiv "ID" size "ID
+                   " parent "ID" maxfr "ID"\n", j, nels,
+                   Nv [j], Fsize [j], Parent [j], Fsize [j])) ;
+               /* this is an element */
+               /* dump the link list of children */
+               nchild = 0 ;
+               AMD_DEBUG1 (("    Children: ")) ;
+               for (ff = Child [j] ; ff != EMPTY ; ff = Sibling [ff])
+               {
+                   AMD_DEBUG1 ((ID" ", ff)) ;
+                   ASSERT (Parent [ff] == j) ;
+                   nchild++ ;
+                   ASSERT (nchild < nn) ;
+               }
+               AMD_DEBUG1 (("\n")) ;
+               parent = Parent [j] ;
+               if (parent != EMPTY)
+               {
+                   ASSERT (Nv [parent] > 0) ;
+               }
+               nels++ ;
+           }
+       }
+    }
+    AMD_DEBUG1 (("\n\nGo through the children of each node, and put\n"
+                "the biggest child last in each list:\n")) ;
+#endif
+
+    /* --------------------------------------------------------------------- */
+    /* place the largest child last in the list of children for each node */
+    /* --------------------------------------------------------------------- */
+
+    for (i = 0 ; i < nn ; i++)
+    {
+       if (Nv [i] > 0 && Child [i] != EMPTY)
+       {
+
+#ifndef NDEBUG
+           Int nchild ;
+           AMD_DEBUG1 (("Before partial sort, element "ID"\n", i)) ;
+           nchild = 0 ;
+           for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+           {
+               ASSERT (f >= 0 && f < nn) ;
+               AMD_DEBUG1 (("      f: "ID"  size: "ID"\n", f, Fsize [f])) ;
+               nchild++ ;
+               ASSERT (nchild <= nn) ;
+           }
+#endif
+
+           /* find the biggest element in the child list */
+           fprev = EMPTY ;
+           maxfrsize = EMPTY ;
+           bigfprev = EMPTY ;
+           bigf = EMPTY ;
+           for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+           {
+               ASSERT (f >= 0 && f < nn) ;
+               frsize = Fsize [f] ;
+               if (frsize >= maxfrsize)
+               {
+                   /* this is the biggest seen so far */
+                   maxfrsize = frsize ;
+                   bigfprev = fprev ;
+                   bigf = f ;
+               }
+               fprev = f ;
+           }
+           ASSERT (bigf != EMPTY) ;
+
+           fnext = Sibling [bigf] ;
+
+           AMD_DEBUG1 (("bigf "ID" maxfrsize "ID" bigfprev "ID" fnext "ID
+               " fprev " ID"\n", bigf, maxfrsize, bigfprev, fnext, fprev)) ;
+
+           if (fnext != EMPTY)
+           {
+               /* if fnext is EMPTY then bigf is already at the end of list */
+
+               if (bigfprev == EMPTY)
+               {
+                   /* delete bigf from the element of the list */
+                   Child [i] = fnext ;
+               }
+               else
+               {
+                   /* delete bigf from the middle of the list */
+                   Sibling [bigfprev] = fnext ;
+               }
+
+               /* put bigf at the end of the list */
+               Sibling [bigf] = EMPTY ;
+               ASSERT (Child [i] != EMPTY) ;
+               ASSERT (fprev != bigf) ;
+               ASSERT (fprev != EMPTY) ;
+               Sibling [fprev] = bigf ;
+           }
+
+#ifndef NDEBUG
+           AMD_DEBUG1 (("After partial sort, element "ID"\n", i)) ;
+           for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+           {
+               ASSERT (f >= 0 && f < nn) ;
+               AMD_DEBUG1 (("        "ID"  "ID"\n", f, Fsize [f])) ;
+               ASSERT (Nv [f] > 0) ;
+               nchild-- ;
+           }
+           ASSERT (nchild == 0) ;
+#endif
+
+       }
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* postorder the assembly tree */
+    /* --------------------------------------------------------------------- */
+
+    for (i = 0 ; i < nn ; i++)
+    {
+       Order [i] = EMPTY ;
+    }
+
+    k = 0 ;
+
+    for (i = 0 ; i < nn ; i++)
+    {
+       if (Parent [i] == EMPTY && Nv [i] > 0)
+       {
+           AMD_DEBUG1 (("Root of assembly tree "ID"\n", i)) ;
+           k = AMD_post_tree (i, k, Child, Sibling, Order, Stack
+#ifndef NDEBUG
+               , nn
+#endif
+               ) ;
+       }
+    }
+}
diff --git a/deal.II/contrib/umfpack/AMD/Source/amd_preprocess.c b/deal.II/contrib/umfpack/AMD/Source/amd_preprocess.c
new file mode 100644 (file)
index 0000000..db635e2
--- /dev/null
@@ -0,0 +1,225 @@
+/* ========================================================================= */
+/* === AMD_preprocess ====================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,  */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README for License.         */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.           */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* Sorts, removes duplicate entries, and transposes from the nonzero pattern of
+ * a column-form matrix A, to obtain the matrix R.
+ * See amd.h for a complete description of AMD_preprocess 
+ */
+
+#include "amd_internal.h"
+
+GLOBAL Int AMD_preprocess   /* returns AMD_OK if input is OK, AMD_INVALID
+                            * if the matrix is invalid, or AMD_OUT_OF_MEMORY
+                            * if out of memory for the 2n workspace. */
+(
+    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) */
+)
+{
+    /* --------------------------------------------------------------------- */
+    /* local variables */
+    /* --------------------------------------------------------------------- */
+
+    Int *Flag, *W ;
+
+    /* --------------------------------------------------------------------- */
+    /* check inputs (note: fewer restrictions than AMD_order) */
+    /* --------------------------------------------------------------------- */
+
+    if (!AMD_preprocess_valid (n, Ap, Ai) || !Ri || !Rp)
+    {
+       return (AMD_INVALID) ;
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* --------------------------------------------------------------------- */
+
+    W = (Int *) ALLOCATE (MAX (n,1) * sizeof (Int)) ;
+    if (!W)
+    {
+       return (AMD_OUT_OF_MEMORY) ;
+    }
+    Flag = (Int *) ALLOCATE (MAX (n,1) * sizeof (Int)) ;
+    if (!Flag)
+    {
+       FREE (W) ;
+       return (AMD_OUT_OF_MEMORY) ;
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* preprocess the matrix:  sort, remove duplicates, and transpose */
+    /* --------------------------------------------------------------------- */
+
+    AMD_wpreprocess (n, Ap, Ai, Rp, Ri, W, Flag) ;
+
+    /* --------------------------------------------------------------------- */
+    /* free the workspace */
+    /* --------------------------------------------------------------------- */
+
+    FREE (W) ;
+    FREE (Flag) ;
+    return (AMD_OK) ;
+}
+
+
+/* ========================================================================= */
+/* === AMD_wpreprocess ===================================================== */
+/* ========================================================================= */
+
+/* The AMD_wpreprocess routine is not user-callable.  It does not check its
+ * input for errors or allocate workspace (that is done by the user-callable
+ * AMD_preprocess routine).  It does handle the n=0 case. */
+
+GLOBAL void AMD_wpreprocess
+(
+    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 ;
+
+    /* --------------------------------------------------------------------- */
+    /* 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
+    for (j = 0 ; j < n ; j++)
+    {
+       ASSERT (W [j] == Rp [j+1]) ;
+    }
+    ASSERT (AMD_valid (n, n, Rp, Ri)) ;
+#endif
+}
+
+
+/* ========================================================================= */
+/* === AMD_preprocess_valid ================================================ */
+/* ========================================================================= */
+
+/* Not user-callable.  Checks a matrix and returns TRUE if it is valid as input
+ * to AMD_wpreprocess, FALSE otherwise. */
+
+GLOBAL Int AMD_preprocess_valid
+(
+    Int n,
+    const Int Ap [ ],
+    const Int Ai [ ]
+)
+{
+    Int i, j, p, nz ;
+
+    if (n < 0 || !Ai || !Ap)
+    {
+       return (FALSE) ;
+    }
+    nz = Ap [n] ;
+    if (Ap [0] != 0 || nz < 0)
+    {
+       /* column pointers must start at Ap [0] = 0, and Ap [n] must be >= 0 */
+       AMD_DEBUG0 (("column 0 pointer bad or nz < 0\n")) ;
+       return (FALSE) ;
+    }
+    for (j = 0 ; j < n ; j++)
+    {
+       if (Ap [j] > Ap [j+1])
+       {
+           /* column pointers must be ascending */
+           AMD_DEBUG0 (("column "ID" pointer bad\n", j)) ;
+           return (FALSE) ;
+       }
+    }
+    for (p = 0 ; p < nz ; p++)
+    {
+       i = Ai [p] ;
+       AMD_DEBUG3 (("row: "ID"\n", i)) ;
+       if (i < 0 || i >= n)
+       {
+           /* row index out of range */
+           AMD_DEBUG0 (("index out of range, col "ID" row "ID"\n", j, i)) ;
+           return (FALSE) ;
+       }
+    }
+    return (TRUE) ;
+}
diff --git a/deal.II/contrib/umfpack/AMD/Source/amd_valid.c b/deal.II/contrib/umfpack/AMD/Source/amd_valid.c
new file mode 100644 (file)
index 0000000..77e3dea
--- /dev/null
@@ -0,0 +1,78 @@
+/* ========================================================================= */
+/* === AMD_valid =========================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,  */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README for License.         */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.           */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* Check if a column-form matrix is valid or not.  The matrix A is
+ * n_row-by-n_col.  The row indices of entries in column j are in
+ * Ai [Ap [j] ... Ap [j+1]-1].  Required conditions are:
+ *
+ *     n_row >= 0
+ *     n_col >= 0
+ *     nz = Ap [n_col] >= 0        number of entries in the matrix
+ *     Ap [0] == 0
+ *     Ap [j] <= Ap [j+1] for all j in the range 0 to n_col.
+ *     row indices in Ai [Ap [j] ... Ap [j+1]-1] must be sorted in ascending
+ *         order, must be in the range 0 to n_row-1, and no duplicate entries
+ *         can exist.
+ *
+ * Not user-callable.
+ */
+
+#include "amd_internal.h"
+
+GLOBAL Int AMD_valid
+(
+    /* inputs, not modified on output: */
+    Int n_row,         /* A is n_row-by-n_col */
+    Int n_col,
+    const Int Ap [ ],  /* column pointers of A, of size n_col+1 */
+    const Int Ai [ ]   /* row indices of A, of size nz = Ap [n_col] */
+)
+{
+    Int nz, j, p1, p2, ilast, i, p ;
+    if (n_row < 0 || n_col < 0)
+    {
+       AMD_DEBUG0 (("n must be >= 0: "ID" "ID"\n", n_row, n_col)) ;
+       return (FALSE) ;
+    }
+    nz = Ap [n_col] ;
+    if (Ap [0] != 0 || nz < 0)
+    {
+       /* column pointers must start at Ap [0] = 0, and Ap [n] must be >= 0 */
+       AMD_DEBUG0 (("column 0 pointer bad or nz < 0\n")) ;
+       return (FALSE) ;
+    }
+    for (j = 0 ; j < n_col ; j++)
+    {
+       p1 = Ap [j] ;
+       p2 = Ap [j+1] ;
+       AMD_DEBUG2 (("\nColumn: "ID" p1: "ID" p2: "ID"\n", j, p1, p2)) ;
+       if (p1 > p2)
+       {
+           /* column pointers must be ascending */
+           AMD_DEBUG0 (("column "ID" pointer bad\n", j)) ;
+           return (FALSE) ;
+       }
+       ilast = EMPTY ;
+       for (p = p1 ; p < p2 ; p++)
+       {
+           i = Ai [p] ;
+           AMD_DEBUG3 (("row: "ID"\n", i)) ;
+           if (i <= ilast || i >= n_row)
+           {
+               /* row index out of range, or unsorted */
+               AMD_DEBUG0 (("index out of range, col "ID" row "ID"\n", j, i));
+               return (FALSE) ;
+           }
+           ilast = i ;
+       }
+    }
+    return (TRUE) ;
+}
diff --git a/deal.II/contrib/umfpack/AMD/Source/amdbar.f b/deal.II/contrib/umfpack/AMD/Source/amdbar.f
new file mode 100644 (file)
index 0000000..1384392
--- /dev/null
@@ -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/deal.II/contrib/umfpack/Makefile b/deal.II/contrib/umfpack/Makefile
new file mode 100644 (file)
index 0000000..1da96a2
--- /dev/null
@@ -0,0 +1,32 @@
+include ../../common/Make.global_options
+
+# rules
+ifeq ($(enable-shared),yes)
+  lib: $(LIBDIR)/liblac_umfpack.so
+else
+  lib: $(LIBDIR)/liblac_umfpack.a
+endif
+
+
+AMD:
+       cd AMD/Source ; $(MAKE) all
+
+UMFPACK:
+       cd UMFPACK/Source ; $(MAKE) all
+
+
+$(LIBDIR)/liblac_umfpack.so: AMD UMFPACK
+       @echo "=====umfpack==========optimized==$(MT)== Linking library:   $(@F)"
+       @$(SHLIBLD) $(LDFLAGS) -shared -o $@ $D/lib/umfpack/*.o
+
+
+$(LIBDIR)/liblac_umfpack.a: AMD UMFPACK
+       @echo "=====umfpack==========optimized==$(MT)== Linking library:   $(@F)"
+       @$(AR) ru $@ $D/lib/umfpack/*.o
+       @$(RANLIB) $@
+
+
+clean:
+
+
+.PHONY: AMD UMFPACK clean lib
diff --git a/deal.II/contrib/umfpack/README b/deal.II/contrib/umfpack/README
new file mode 100644 (file)
index 0000000..adf016b
--- /dev/null
@@ -0,0 +1,5 @@
+UMFPACK v4.3 and AMD v1.1.
+
+See UMFPACK/README and AMD/README for details.  Documention is in
+UMFPACK/Doc and AMD/Doc.
+
diff --git a/deal.II/contrib/umfpack/README.deal.II b/deal.II/contrib/umfpack/README.deal.II
new file mode 100644 (file)
index 0000000..56c3c41
--- /dev/null
@@ -0,0 +1,14 @@
+This directory is an almost identical copy of the UMFPACK 4.3
+release. The only things I have changed are the Makefiles: they build
+shared libraries instead of static ones if deal.II is so configured,
+and they put the object files somewhere else. This also allowed us to
+get rid of the AMD/Make and UMFPACK/Make subdirectories, since they
+did by hand what we do more elegantly using autoconf and friends.
+Finally, I removed the UMFPACK/Demo directory, since it is rather
+big. I assume that people using UMFPACK from inside deal.II are not
+interested in this, but they can of course download the full UMFPACK
+distribution if they want these files.
+
+UMFPACK is copyrighted by others than the deal.II authors, but
+included by permission. See the AMD/Doc/License and
+UMFPACK/Doc/License files for licensing information.
\ No newline at end of file
diff --git a/deal.II/contrib/umfpack/UMFPACK/Doc/ChangeLog b/deal.II/contrib/umfpack/UMFPACK/Doc/ChangeLog
new file mode 100644 (file)
index 0000000..165d5ef
--- /dev/null
@@ -0,0 +1,334 @@
+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/deal.II/contrib/umfpack/UMFPACK/Doc/License b/deal.II/contrib/umfpack/UMFPACK/Doc/License
new file mode 100644 (file)
index 0000000..20fdc97
--- /dev/null
@@ -0,0 +1,53 @@
+UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.
+Davis.  All Rights Reserved.
+
+UMFPACK License:
+
+    Your use or distribution of UMFPACK or any modified version of
+    UMFPACK implies that you agree to this License.
+
+    THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
+    EXPRESSED OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+
+    Permission is hereby granted to use or copy this program, provided
+    that the Copyright, this License, and the Availability of the original
+    version is retained on all copies.  User documentation of any code that
+    uses UMFPACK or any modified version of UMFPACK code must cite the
+    Copyright, this License, the Availability note, and "Used by permission."
+    Permission to modify the code and to distribute modified code is granted,
+    provided the Copyright, this License, and the Availability note are
+    retained, and a notice that the code was modified is included.  This
+    software was developed with support from the National Science Foundation,
+    and is provided to you free of charge.
+
+Availability:
+
+    http://www.cise.ufl.edu/research/sparse/umfpack
+
+--------------------------------------------------------------------------------
+
+AMD Version 1.1 (Jan. 10, 2004),  Copyright (c) 2004 by Timothy A.
+Davis, Patrick R. Amestoy, and Iain S. Duff.  All Rights Reserved.
+
+AMD License:
+
+    Your use or distribution of AMD or any modified version of
+    AMD implies that you agree to this License.
+
+    THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
+    EXPRESSED OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+
+    Permission is hereby granted to use or copy this program, provided
+    that the Copyright, this License, and the Availability of the original
+    version is retained on all copies.  User documentation of any code that
+    uses AMD or any modified version of AMD code must cite the
+    Copyright, this License, the Availability note, and "Used by permission."
+    Permission to modify the code and to distribute modified code is granted,
+    provided the Copyright, this License, and the Availability note are
+    retained, and a notice that the code was modified is included.  This
+    software was developed with support from the National Science Foundation,
+    and is provided to you free of charge.
+
+Availability:
+
+    http://www.cise.ufl.edu/research/sparse/amd
diff --git a/deal.II/contrib/umfpack/UMFPACK/Doc/Makefile b/deal.II/contrib/umfpack/UMFPACK/Doc/Makefile
new file mode 100644 (file)
index 0000000..a7458bb
--- /dev/null
@@ -0,0 +1,52 @@
+#-------------------------------------------------------------------------------
+# UMFPACK Makefile for compiling on Unix systems (for GNU or original make)
+#-------------------------------------------------------------------------------
+
+all: dist
+
+include ../Make/Make.include
+
+#-------------------------------------------------------------------------------
+# 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
+
+#-------------------------------------------------------------------------------
+# 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_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)
+       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/deal.II/contrib/umfpack/UMFPACK/Doc/QuickStart.pdf b/deal.II/contrib/umfpack/UMFPACK/Doc/QuickStart.pdf
new file mode 100644 (file)
index 0000000..43c785c
Binary files /dev/null and b/deal.II/contrib/umfpack/UMFPACK/Doc/QuickStart.pdf differ
diff --git a/deal.II/contrib/umfpack/UMFPACK/Doc/QuickStart.tex b/deal.II/contrib/umfpack/UMFPACK/Doc/QuickStart.tex
new file mode 100644 (file)
index 0000000..eba0ee3
--- /dev/null
@@ -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 4.3 Quick Start Guide}
+\date{Jan. 16, 2004}
+\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}
+%-------------------------------------------------------------------------------
+
+Technical Report TR-04-003
+
+UMFPACK Version 4.3 (Jan. 16, 2004), Copyright\copyright 2004 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 Version 4.0 is a built-in routine in MATLAB 6.5, 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 31 user-callable routines and one
+include file.  Twenty-seven 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.
+
+%-------------------------------------------------------------------------------
+\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,
+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 v4.3 and AMD v1.1 (or AMD v1.0) to use UMFPACK.
+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 AMD/Make}
+and {\tt UMFPACK/Make} directories.  You can edit the {\tt Make.include}
+files in those directories to customize the compilation.  The default
+settings will work on most systems, except that UMFPACK will be compiled so
+that it does not use the BLAS.  Sample configuration files 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 Make.include}
+file or your system-specific configuration file such as {\tt Make.linux},
+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 Make.include} 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 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 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 -DCBLAS} if you have the C-BLAS.
+\item {\tt -DNSUNPERF} if you are on Solaris but do not have the Sun
+    Performance Library.
+\item {\tt -DNSCSL} if you on SGI IRIX but do not have the SCSL BLAS library.
+\item {\tt -DLONGBLAS} if your BLAS can take {\tt long} integer input
+    arguments.
+\item Options for controlling how C calls the Fortran BLAS:
+    {\tt -DBLAS\_BY\_VALUE}, {\tt -DBLAS\_NO\_UNDERSCORE},
+    and {\tt -DBLAS\_CHAR\_ARG}.  These are 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 -DLP64} if you are compiling in the LP64 model (32 bit {\tt int}'s,
+    64 bit {\tt long}'s, and 64 bit pointers).
+\item {\tt -DNUTIL} if you wish to compile the MATLAB-callable
+    UMFPACK mexFunction with the {\tt mxMalloc}, {\tt mxRealloc}
+    and {\tt mxFree} routines, instead of the undocumented (but
+    superior) {\tt utMalloc}, {\tt utRealloc}, and {\tt utFree}
+    routines.
+\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 normally off by default, except when the {\tt gcc}
+    compiler is used.
+\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@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 occured.  Your solution will contain Inf's
+                and/or NaN's.  Some parts of the solution may be valid.  For
+                example, solving Ax=b with
+
+                A = [2 0]  b = [ 1 ]  returns x = [ 0.5 ]
+                    [0 0]      [ 0 ]              [ Inf ]
+
+            UMFPACK_ERROR_out_of_memory
+
+                Insufficient memory to solve the linear system.
+
+            UMFPACK_ERROR_argument_missing
+
+                One or more required arguments are missing.  The B 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/deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.bib b/deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.bib
new file mode 100644 (file)
index 0000000..691ba73
--- /dev/null
@@ -0,0 +1,324 @@
+@string{TOMS = "ACM Trans. Math. Softw."}
+@string{SIMAX = "SIAM J. Matrix Anal. Applic."}
+@string{SINUM = "SIAM J. Numer. Anal."}
+@string{SIAMJSC = "SIAM J. Sci. Comput."}
+@string{SIAMJSSC = "SIAM J. Sci. Statist. Comput."}
+@string{IJNME = "Internat. J. Numer. Methods Eng."}
+@string{SIAMJADM = "SIAM J. Alg. Disc. Meth."}
+
+@article{AmestoyDavisDuff96,
+       author={Amestoy, P. R. and Davis, T. A. and Duff, I. S.},
+       title={An approximate minimum degree ordering algorithm},
+       journal=SIMAX,
+       year={1996}
+       ,volume={17}
+       ,number={4}
+       ,pages={886-905}}
+
+@article{AmestoyDavisDuff03,
+       author={Amestoy, P. R. and Davis, T. A. and Duff, I. S.},
+       title={Algorithm 8xx: {AMD}, an approximate minimum degree ordering algorithm},
+       journal=TOMS,
+       year={2003 (under submission)},
+       note={Also TR-03-010 at www.cise.ufl.edu/tech-reports.}
+       }
+
+@techreport{AmestoyDavisDuff03_user,
+       author={Amestoy, P. R. and Davis, T. A. and Duff, I. S.},
+       title={{AMD} Version 1.0 User Guide},
+       institution={CISE Dept., Univ. of Florida},
+       year={2003}
+       ,number={TR-03-011}
+       ,address={Gainesville, FL}
+       ,note={www.cise.ufl.edu/tech-reports.}
+       }
+
+@article{Davis03,
+       author={Davis, T. A.},
+       title={A column pre-ordering strategy for the unsymmetric-pattern multifrontal method},
+       journal=TOMS,
+       year={2003 (under submission)}
+       ,note={Also TR-03-006 at www.cise.ufl.edu/tech-reports.}
+       }
+
+@article{Davis03_algo,
+       author={Davis, T. A.},
+       title={Algorithm 8xx:  {UMFPACK V4.3}, an unsymmetric-pattern multifrontal method},
+       journal=TOMS,
+       year={2004 (under submission)}
+       ,note={Also TR-04-004 at www.cise.ufl.edu/tech-reports.}
+       }
+
+@techreport{Davis03_umf,
+       author={Davis, T. A.},
+       title={{UMFPACK} Version 4.3 User Guide},
+       institution={Univ. of Florida, CISE Dept.},
+       year={2004}
+       ,number={TR-04-003}
+       ,address={Gainesville, FL}
+       ,note={(www.cise.ufl.edu/tech-reports)}
+       }
+
+@techreport{Davis03_umfquick,
+       author={Davis, T. A.},
+       title={{UMFPACK} Version 4.3 Quick Start Guide},
+       institution={Univ. of Florida, CISE Dept.},
+       year={2004}
+       ,number={TR-04-005}
+       ,address={Gainesville, FL}
+       ,note={(www.cise.ufl.edu/tech-reports)}
+       }
+
+@article{DavisDuff97,
+       author={Davis, T. A. and Duff, I. S.},
+       title={An unsymmetric-pattern multifrontal method for sparse {LU} factorization},
+       journal=SIMAX,
+       year={1997}
+       ,volume={18}
+       ,number={1}
+       ,pages={140-158}}
+
+@article{DavisDuff99,
+       author={Davis, T. A. and Duff, I. S.},
+       title={A combined unifrontal/multifrontal method for unsymmetric sparse matrices},
+       journal=TOMS,
+       volume={25},
+       number={1},
+       pages={1-19},
+       year={1999}}
+
+@article{SuperLU99,
+       author={Demmel, J. W. and Eisenstat, S. C. and Gilbert, J. R. and Li, X. S. and Liu, J. W. H.},
+       title={A supernodal approach to sparse partial pivoting},
+       journal=SIMAX,
+       year={1999}
+       ,volume={20}
+       ,number={3}
+       ,pages={720-755}
+       ,note={www.netlib.org}
+       }
+
+@article{ACM679a,
+       author={Dongarra, J. J. and Du Croz, J. and Duff, I. S. and Hammarling, S.},
+       title={A set of level-3 basic linear algebra subprograms},
+       journal=TOMS,
+       year={1990}
+       ,volume={16}
+       ,number={1}
+       ,pages={1--17}}
+
+@article{netlib,
+       author={Dongarra, J. J. and Grosse, E.},
+       title={Distribution of mathematical software via electronic mail},
+       journal={Comm. ACM},
+       year={1987}
+       ,volume={30}
+       ,pages={403-407}
+       ,note={www.netlib.org}
+       }
+
+@article{Duff78b,
+       author={Duff, I. S. and Reid, J. K.},
+       year={1978},
+       title={Algorithm 529: Permutations to Block Triangular Form},
+       journal=TOMS,
+       volume={4},
+       annote={f},
+       number={2},
+       pages={189-192},
+       keywords={102 ordering block triangular form}}
+
+@article{Duff81b,
+       author={Duff, I. S.},
+       year={1981},
+       title={Algorithm 575: Permutations for a Zero-Free Diagonal},
+       journal=TOMS,
+       annote={f},
+       volume={7},
+       pages={387-390},
+       keywords={ordering, zero-free diagonal}}
+
+@techreport{GotoVandeGeijn02,
+       author = {Goto, K. and van de Geijn, R.},
+       title = {On Reducing {TLB} Misses in Matrix Multiplication, {FLAME} Working Note 9},
+       institution={The University of Texas at Austin, Department of Computer Sciences},
+       number={TR-2002-55},
+       month={Nov.},
+       year={2002}}
+
+@article{GeorgeNg85,
+       author={George, A. and Ng, E. G.},
+       year={1985},
+       title={An Implementation of {G}aussian Elimination with
+               Partial Pivoting for Sparse Systems},
+       journal=SIAMJSSC,
+       volume={6},
+       number={2},
+       pages={390-409}}
+
+@article{GeorgeNg87,
+       author={George, A. and Ng, E. G.},
+       year={1987},
+       title={Symbolic Factorization for Sparse {G}aussian Elimination
+               with Partial Pivoting},
+       journal={SIAM J. Sci. Statist. Comput.},
+       volume={8},
+       number={6},
+       pages={877-898}}
+
+@article{GilbertMolerSchreiber,
+       author={Gilbert, J. R. and Moler, C. and Schreiber, R.},
+       title={Sparse matrices in {MATLAB}:  design and implementation},
+       journal=SIMAX,
+       year={1992}
+       ,volume={13}
+       ,number={1}
+       ,pages={333-356}}
+
+@article{GilbertPeierls88,
+       author={Gilbert, J. R. and Peierls, T.},
+       year={1988},
+       title={Sparse Partial Pivoting in Time Proportional to Arithmetic Operations},
+       journal={SIAM J. Sci. Statist. Comput.},
+       volume={9},
+       pages={862-874}}
+
+@article{Gustavson78,
+       author={Gustavson, F. G.},
+       year={1978},
+       title={Two Fast Algorithms for Sparse Matrices: Multiplication and Permuted Transposition},
+       journal=TOMS,
+       volume={4},
+       number={3},
+       pages={250-269}}
+
+@techreport{Larimore98,
+       author={Larimore, S. I.},
+       title={An approximate minimum degree column ordering algorithm},
+       institution={Univ. of Florida, CISE Dept.},
+       year={1998}
+       ,number={TR-98-016}
+       ,address={Gainesville, FL}
+       ,note={www.cise.ufl.edu/tech-reports}}
+
+@techreport{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},
+       institution={Univ. of Florida, CISE Dept.},
+       year={2000}
+       ,number={TR-00-005}
+       ,address={Gainesville, FL}
+       ,month={October}
+       ,note={(www.cise.ufl.edu/tech-reports. Submitted to ACM Trans. Math. Softw.)}
+       }
+
+@techreport{DavisGilbertLarimoreNg00_algo,
+       author={Davis, T. A. and Gilbert, J. R. and Larimore, S. I. and Ng, E. G.},
+       title={Algorithm 8xx:  {COLAMD}, a column approximate minimum degree ordering algorithm},
+       institution={Univ. of Florida, CISE Dept.},
+       year={2000}
+       ,number={TR-00-006}
+       ,address={Gainesville, FL}
+       ,month={October}
+       ,note={(www.cise.ufl.edu/tech-reports. Submitted to ACM Trans. Math. Softw.)}
+       }
+
+
+@INCOLLECTION{GilbertNg93,
+  author = {J. R. Gilbert and E. G. Ng},
+  editor = {A. George and J. R. Gilbert and J. W.H. Liu},
+  year = 1993,
+  title = {Predicting Structure in Nonsymmetric Sparse Matrix Factorizations},
+  booktitle = {Graph Theory and Sparse Matrix Computation},
+  series = {Volume 56 of the {IMA} Volumes in Mathematics and its Applications},
+  pages = {107-139},
+  publisher = {Springer-Verlag}
+}
+
+
+@techreport{ATLAS,
+       author={Whaley, R. C and Petitet, A. and Dongarra, J. J.},
+       title={Automated Emperical Optimization of Software and the {ATLAS} Project},
+       institution={Computer Science Department, The University of Tennessee},
+       year={2000}
+       ,number={LAPACK Working Note 147}
+       ,month={September}
+       ,note={www.netlib.org/atlas}
+       }
+
+@article{DaydeDuff99,
+       author = "M. J. Dayd\'{e} and I. S. Duff",
+       title = "The {RISC} {BLAS}: A Blocked Implementation of Level 3 {BLAS} for {RISC} Processors",
+       journal = TOMS,
+       volume = "25",
+       number = "3",
+       month = {Sept.},
+       year ="1999"
+       }
+
+
+@article{ardd:89,
+   author = {M. Arioli and J. W. Demmel and I. S. Duff},
+   year = "1989",
+   title = {Solving sparse linear systems with sparse backward error},
+   journal = SIMAX,
+   volume  = {10},
+   pages   = {165-190}
+}
+
+
+@article{DavisHager99,
+       author={Davis, T. A. and Hager, W. W.},
+       title={Modifying a sparse {C}holesky factorization},
+       journal=SIMAX,
+       year={1999}
+       ,volume={20}
+       ,number={3}
+       ,pages={606-627}
+       }
+
+
+@article{dusc:96,
+       author = {I. S. Duff and J. A. Scott},
+       title = {The design of a new frontal code for solving sparse unsymmetric systems},
+       journal = TOMS,
+       year = "1996",
+       volume = "22",
+       number = "1",
+       pages = "30-45"
+       }
+
+
+@article{Duff78a,
+       author={Duff, I. S. and Reid, J. K.},
+       year={1978},
+       title={An Implementation of {T}arjan's Algorithm for the Block Triangularization of a Matrix},
+       journal=TOMS,
+       volume={4},
+       number={2},
+       pages={137-147}
+       }
+
+@book{GeorgeLiu,
+       author={George, A. and Liu, J. W. H.},
+       year={1981},
+       title={Computer Solution of Large Sparse Positive Definite Systems},
+       publisher={Englewood Cliffs, New Jersey:  Prentice-Hall}
+       }
+
+@article{GilbertNgPeyton94,
+       author={Gilbert, J. R. and Ng, E. G. and Peyton, B. W.},
+       title={An efficient algorithm to compute row and column counts for sparse {C}holesky factorization},
+       journal=SIMAX,
+       year={1994}
+       ,volume={15}
+       ,number={4}
+       ,pages={1075-1091}
+       }
+
+@techreport{DuffGrimesLewis87b,
+       author={Duff, I. S. and Grimes, R. G. and Lewis, J. G.},
+       year={1987},
+       title={Users' Guide for the Harwell-Boeing Sparse Matrix Test Collection},
+       institution={AERE Harwell Laboratory, United Kingdom Atomic Energy Authority}}
+
diff --git a/deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.pdf b/deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.pdf
new file mode 100644 (file)
index 0000000..3aab8d8
Binary files /dev/null and b/deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.pdf differ
diff --git a/deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.sed1 b/deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.sed1
new file mode 100644 (file)
index 0000000..c44a640
--- /dev/null
@@ -0,0 +1,32 @@
+/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
diff --git a/deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.sed2 b/deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.sed2
new file mode 100644 (file)
index 0000000..0df47d9
--- /dev/null
@@ -0,0 +1,3 @@
+/[/][*]/d
+/[*][/]/d
+/INCLUDE umfpack/d
diff --git a/deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.stex b/deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.stex
new file mode 100644 (file)
index 0000000..99dc586
--- /dev/null
@@ -0,0 +1,2554 @@
+%-------------------------------------------------------------------------------
+% 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 4.3 User Guide}
+\date{Jan. 16, 2004}
+\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.
+
+UMFPACK Version 4.3 (Jan. 16, 2004), Copyright\copyright 2004 by Timothy A.
+Davis.  All Rights Reserved.
+
+{\bf UMFPACK License:}
+    Your use or distribution of UMFPACK or any modified version of
+    UMFPACK implies that you agree to this License.
+
+    THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
+    EXPRESSED OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+
+    Permission is hereby granted to use or copy this program, provided
+    that the Copyright, this License, and the Availability of the original
+    version is retained on all copies.  User documentation of any code that
+    uses UMFPACK or any modified version of UMFPACK code must cite the
+    Copyright, this License, the Availability note, and ``Used by permission.''
+    Permission to modify the code and to distribute modified code is granted,
+    provided the Copyright, this License, and the Availability note are
+    retained, and a notice that the code was modified is included.  This
+    software was developed with support from the National Science Foundation,
+    and is provided to you free of charge.
+
+{\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 4.3 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}, available at
+http://www.cise.ufl.edu/tech-reports.
+
+%-------------------------------------------------------------------------------
+\section{Availability}
+%-------------------------------------------------------------------------------
+
+In addition to appearing as a Collected Algorithm of the ACM,
+UMFPACK Version 4.3 is available at http://www.cise.ufl.edu/research/sparse.
+An earlier version (Version 4.0) is included as a built-in routine in MATLAB
+6.5.  Version 4.0 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}.
+Version 4.3 (and v4.2 and 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 since Version 4.1}
+%-------------------------------------------------------------------------------
+
+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.
+
+%-------------------------------------------------------------------------------
+\section{Primary changes in Version 4.1 (since Version 4.0)}
+%-------------------------------------------------------------------------------
+
+A detailed list of changes is in the {\tt ChangeLog} file.  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.0 is a built-in
+routine in MATLAB 6.5, 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.  UMFPACK will print these statistics if you turn
+on the sparse matrix monitor flag with {\tt spparms ('spumoni', 1)}.
+The UMFPACK printing level parameter described in Section~\ref{Reporting}
+is set to {\tt spumoni} plus 1.  Type {\tt help umfpack} for more information.
+
+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 column pre-ordering.
+\end{minipage}
+&
+\begin{minipage}[t]{2.2in}
+\begin{verbatim}
+S = spones (A) ;
+Q = symamd (S+S') ;
+x = umfpack (A,Q,'\',b) ;
+\end{verbatim}
+\end{minipage}
+&
+\begin{minipage}[t]{2.2in}
+\begin{verbatim}
+spparms ('autommd',0) ;
+S = spones (A) ;
+Q = symamd (S+S') ;
+x = A (:,Q) \ b ;
+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}
+\end{minipage}
+&
+\begin{minipage}[t]{2.2in}
+\begin{verbatim}
+x = b / A ;
+\end{verbatim}
+\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, 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, which uses UMFPACK v4.0 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.  The strategy works fine
+when {\tt malloc} or the internal memory allocator {\tt utMalloc} are used
+instead, since those routines return {\tt NULL} on failure, and do not terminate
+the mexFunction.  The {\tt umfpack} mexFunction can be compiled to use
+{\tt utMalloc}, but this is an internal undocumented utility routine in MATLAB,
+and thus using {\tt utMalloc} might not always be successful.
+To use the documented {\tt mxMalloc} routine instead, compile the
+mexFunction with the {\tt -DNUTIL} flag enabled.
+
+%-------------------------------------------------------------------------------
+\section{Using UMFPACK in a C program}
+\label{C}
+%-------------------------------------------------------------------------------
+
+The C-callable UMFPACK library consists of 31 user-callable routines and one
+include file.  Twenty-seven 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 long} integers.
+\item {\tt umfpack\_zi\_*}: complex double precision, {\tt int} integers.
+\item {\tt umfpack\_zl\_*}: complex double precision, {\tt long} integers.
+\end{enumerate}
+where {\tt *} denotes the specific name of one of the 27 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 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 27 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/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 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
+{\tt Make.alpha}, {\tt Make.sgi}, and {\tt Make.solaris}.
+
+%-------------------------------------------------------------------------------
+\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.
+
+%-------------------------------------------------------------------------------
+\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 long} version of UMFPACK:
+
+{\footnotesize
+\begin{verbatim}
+     long Ap [n+1] ;
+     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}
+}
+
+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]}.
+
+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 long} version:
+
+{\footnotesize
+\begin{verbatim}
+     long Ti [nz] ;
+     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.  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.  This routine is new to Version 4.1.
+
+\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}.
+
+%-------------------------------------------------------------------------------
+\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.
+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\_*\_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.
+
+%-------------------------------------------------------------------------------
+\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.
+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 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.
+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 will increase in future versions.
+
+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 v4.3.  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.  Currently, the only warning code is when the
+matrix is singular.  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\_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.
+    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@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 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 long}.
+Similarly, the complex, {\tt 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 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.  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] ;
+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) ;
+\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}
+}
+
+%-------------------------------------------------------------------------------
+\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}
+}
+
+%-------------------------------------------------------------------------------
+\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)] ;
+
+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) ;
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\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}
+}
+
+
+
+
+
+%-------------------------------------------------------------------------------
+\section{Synopsis of 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}
+}
+
+%-------------------------------------------------------------------------------
+\section{Synopsis of 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 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 v4.3 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}
+}
+
+%-------------------------------------------------------------------------------
+\section{Installing the C library}
+\label{Install}
+%-------------------------------------------------------------------------------
+
+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 v4.3 and AMD v1.1 (or AMD v1.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 AMD/Make}
+and {\tt UMFPACK/Make} directories (the \newline
+{\tt UMFPACK/Make} directory is actually
+just a symbolic link to {\tt AMD/Make}\footnote{Windows might not extract
+the symbolic link {\tt UMFPACK/Make} correctly.  If it doesn't, simply
+create the {\tt UMFPACK/Make} folder by copying it from {\tt AMD/Make}.}).
+You can edit the {\tt Make.include}
+files in either of those directories to customize the compilation.  The default
+settings will work on most systems, except that UMFPACK will be compiled so
+that it does not use the BLAS.  Sample configuration files 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 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 Make.include}
+file or your system-specific configuration file such as {\tt Make.linux},
+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 Make.include} 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}.
+    Add {\tt -DLP64} if you are compiling in 64-bit mode
+    (32 bit {\tt int}'s, 64 bit {\tt long}'s, and 64 bit pointers).
+\item {\tt 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.  An example is provided in
+    the {\tt Make/Make.include} 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).
+\end{itemize}
+
+The {\tt 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 -DCBLAS} if you have the C-BLAS \cite{ATLAS}.
+\item {\tt -DNSUNPERF} if you are on Solaris but do not have the Sun
+    Performance Library (for the BLAS).
+\item {\tt -DNSCSL} if you on SGI IRIX but do not have the SCSL BLAS library.
+\item {\tt -DLONGBLAS} if your BLAS can take {\tt long} integer input
+    arguments.  If not defined, then the {\tt umfpack\_*l\_*} versions of
+    UMFPACK that use {\tt long} integers do not call the BLAS.
+    This flag is set internally when using the Sun Performance BLAS
+    or SGI's SCSL BLAS (both have 64-bit versions of the BLAS).
+\item Options for controlling how C calls the Fortran BLAS:
+    {\tt -DBLAS\_BY\_VALUE}, {\tt -DBLAS\_NO\_UNDERSCORE},
+    and {\tt -DBLAS\_CHAR\_ARG}.  These are set automatically for Windows,
+    Sun Solaris, SGI Irix, Red Hat Linux, Compaq Alpha, and
+    AIX (the IBM RS 6000).  They are ignored if you are using
+    the C-BLAS interface to the BLAS.
+\item {\tt -DGETRUSAGE} if you have the {\tt getrusage} function.
+\item {\tt -DNUTIL} if you wish to compile the MATLAB-callable
+    UMFPACK mexFunction with the {\tt mxMalloc}, {\tt mxRealloc}
+    and {\tt mxFree} routines, instead of the undocumented (but
+    superior) {\tt utMalloc}, {\tt utRealloc}, and {\tt utFree}
+    routines.  The default is to use the {\tt ut*} routines on
+    Unix, and the {\tt mx*} routines on Windows.
+\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 Make/Make.<arch>}
+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 Make/Make.<arch>} 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.
+
+%-------------------------------------------------------------------------------
+\section{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.  This method of creating the UMFPACK mexFunction
+has been tested with MATLAB 5.3, 6.1, and 6.5.
+
+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.
+
+%-------------------------------------------------------------------------------
+\section{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.
+
+%-------------------------------------------------------------------------------
+\section{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 UMFPACK Version 4.3, 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 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}).
+
+\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.
+
+\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.
+
+\item The ability to use user-provided {\tt malloc}, {\tt free}, and
+    {\tt realloc} memory allocation routines.  Note that UMFPACK makes very
+    few calls to these routines.  You can do this at compile-time by
+    modifying the definitions of {\tt ALLOCATE}, {\tt FREE}, and
+    {\tt REALLOCATE} in the file {\tt umf\_internal.h}.  Be sure to document
+    your changes carefully when you change UMFPACK source code.
+
+\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.
+
+\item The complex versions could use ANSI C99 {\tt double \_Complex} arguments,
+    and support the use of interleaved real/imaginary parts as input and output
+    arguments.  The \newline
+    {\tt umfpack\_*\_report\_vector} routine is one example.
+
+\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 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
+\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/deal.II/contrib/umfpack/UMFPACK/Include/umfpack.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack.h
new file mode 100644 (file)
index 0000000..c1918f6
--- /dev/null
@@ -0,0 +1,405 @@
+/* ========================================================================== */
+/* === umfpack.h ============================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    This is the umfpack.h include file, and should be included in all user code
+    that uses UMFPACK.  Do not include any of the umf_* header files in user
+    code.  All routines in UMFPACK starting with "umfpack_" are user-callable.
+    All other routines are prefixed "umf_XY_", (where X is d or z, and Y is
+    i or l) and are not user-callable.
+*/
+
+#ifndef UMFPACK_H
+#define UMFPACK_H
+
+/* -------------------------------------------------------------------------- */
+/* size of Info and Control arrays */
+/* -------------------------------------------------------------------------- */
+
+#define UMFPACK_INFO 90                /* these might be larger in future versions */
+#define UMFPACK_CONTROL 20
+
+/* -------------------------------------------------------------------------- */
+/* User-callable routines */
+/* -------------------------------------------------------------------------- */
+
+/* Primary routines: */
+#include "umfpack_symbolic.h"
+#include "umfpack_numeric.h"
+#include "umfpack_solve.h"
+#include "umfpack_free_symbolic.h"
+#include "umfpack_free_numeric.h"
+
+/* Alternative routines: */
+#include "umfpack_defaults.h"
+#include "umfpack_qsymbolic.h"
+#include "umfpack_wsolve.h"
+
+/* Matrix manipulation routines: */
+#include "umfpack_triplet_to_col.h"
+#include "umfpack_col_to_triplet.h"
+#include "umfpack_transpose.h"
+#include "umfpack_scale.h"
+
+/* Getting the contents of the Symbolic and Numeric opaque objects: */
+#include "umfpack_get_lunz.h"
+#include "umfpack_get_numeric.h"
+#include "umfpack_get_symbolic.h"
+#include "umfpack_save_numeric.h"
+#include "umfpack_load_numeric.h"
+#include "umfpack_save_symbolic.h"
+#include "umfpack_load_symbolic.h"
+
+/* Reporting routines (the above 14 routines print nothing): */
+#include "umfpack_report_status.h"
+#include "umfpack_report_info.h"
+#include "umfpack_report_control.h"
+#include "umfpack_report_matrix.h"
+#include "umfpack_report_triplet.h"
+#include "umfpack_report_vector.h"
+#include "umfpack_report_symbolic.h"
+#include "umfpack_report_numeric.h"
+#include "umfpack_report_perm.h"
+
+/* Utility routines: */
+#include "umfpack_timer.h"
+#include "umfpack_tictoc.h"
+
+/* -------------------------------------------------------------------------- */
+/* Version, copyright, and license */
+/* -------------------------------------------------------------------------- */
+
+#define UMFPACK_VERSION "UMFPACK V4.3 (Jan. 16, 2004)"
+
+#define UMFPACK_COPYRIGHT \
+"UMFPACK:  Copyright (c) 2004 by Timothy A. Davis.  All Rights Reserved.\n"
+
+#define UMFPACK_LICENSE_PART1 \
+"\nUMFPACK License:\n" \
+"\n" \
+"   Your use or distribution of UMFPACK or any modified version of\n" \
+"   UMFPACK implies that you agree to this License.\n" \
+"\n" \
+"   THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY\n" \
+"   EXPRESSED OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.\n"
+#define UMFPACK_LICENSE_PART2 \
+"\n" \
+"   Permission is hereby granted to use or copy this program, provided\n" \
+"   that the Copyright, this License, and the Availability of the original\n" \
+"   version is retained on all copies.  User documentation of any code that\n" \
+"   uses UMFPACK or any modified version of UMFPACK code must cite the\n" \
+"   Copyright, this License, the Availability note, and \"Used by permission.\"\n"
+#define UMFPACK_LICENSE_PART3 \
+"   Permission to modify the code and to distribute modified code is granted,\n" \
+"   provided the Copyright, this License, and the Availability note are\n" \
+"   retained, and a notice that the code was modified is included.  This\n" \
+"   software was developed with support from the National Science Foundation,\n" \
+"   and is provided to you free of charge.\n" \
+"\n" \
+"Availability: http://www.cise.ufl.edu/research/sparse/umfpack\n" \
+"\n"
+
+/* -------------------------------------------------------------------------- */
+/* contents of Info */
+/* -------------------------------------------------------------------------- */
+
+/* Note that umfpack_report.m must coincide with these definitions. */
+
+/* returned by all routines that use Info: */
+#define UMFPACK_STATUS 0       /* UMFPACK_OK, or other result */
+#define UMFPACK_NROW 1         /* n_row input value */
+#define UMFPACK_NCOL 16                /* n_col input value */
+#define UMFPACK_NZ 2           /* # of entries in A */
+
+/* computed in UMFPACK_*symbolic and UMFPACK_numeric: */
+#define UMFPACK_SIZE_OF_UNIT 3         /* sizeof (Unit) */
+
+/* computed in UMFPACK_*symbolic: */
+#define UMFPACK_SIZE_OF_INT 4          /* sizeof (int) */
+#define UMFPACK_SIZE_OF_LONG 5         /* sizeof (long) */
+#define UMFPACK_SIZE_OF_POINTER 6      /* sizeof (void *) */
+#define UMFPACK_SIZE_OF_ENTRY 7                /* sizeof (Entry), real or complex */
+#define UMFPACK_NDENSE_ROW 8           /* number of dense rows */
+#define UMFPACK_NEMPTY_ROW 9           /* number of empty rows */
+#define UMFPACK_NDENSE_COL 10          /* number of dense rows */
+#define UMFPACK_NEMPTY_COL 11          /* number of empty rows */
+#define UMFPACK_SYMBOLIC_DEFRAG 12     /* # of memory compactions */
+#define UMFPACK_SYMBOLIC_PEAK_MEMORY 13        /* memory used by symbolic analysis */
+#define UMFPACK_SYMBOLIC_SIZE 14       /* size of Symbolic object, in Units */
+#define UMFPACK_SYMBOLIC_TIME 15       /* time (sec.) for symbolic analysis */
+#define UMFPACK_SYMBOLIC_WALLTIME 17   /* wall clock time for sym. analysis */
+#define UMFPACK_STRATEGY_USED 18       /* strategy used: sym, unsym, 2by2 */
+#define UMFPACK_ORDERING_USED 19       /* ordering used: colamd, amd, given */
+#define UMFPACK_QFIXED 31              /* whether Q is fixed or refined */
+#define UMFPACK_DIAG_PREFERRED 32      /* whether diagonal pivoting attempted*/
+#define UMFPACK_PATTERN_SYMMETRY 33    /* symmetry of pattern of S */
+#define UMFPACK_NZ_A_PLUS_AT 34                /* nnz (S+S'), excl. diagonal */
+#define UMFPACK_NZDIAG 35              /* nnz (diag (S)) */
+
+/* AMD statistics, computed in UMFPACK_*symbolic: */
+#define UMFPACK_SYMMETRIC_LUNZ 36      /* nz in L+U, if AMD ordering used */
+#define UMFPACK_SYMMETRIC_FLOPS 37     /* flops for LU, if AMD ordering used */
+#define UMFPACK_SYMMETRIC_NDENSE 38    /* # of "dense" rows/cols in S+S' */
+#define UMFPACK_SYMMETRIC_DMAX 39      /* max nz in cols of L, for AMD */
+
+/* statistics for 2-by-2 strategy */
+#define UMFPACK_2BY2_NWEAK 51              /* number of weak diagonal entries*/
+#define UMFPACK_2BY2_UNMATCHED 52          /* # of weak diagonals not matched*/
+#define UMFPACK_2BY2_PATTERN_SYMMETRY 53    /* symmetry of pattern of P*S */
+#define UMFPACK_2BY2_NZ_PA_PLUS_PAT 54     /* nz in PS+(PS)' */
+#define UMFPACK_2BY2_NZDIAG 55             /* nz on diagonal of PS+(PS)' */
+
+/* statistcs for singleton pruning */
+#define UMFPACK_COL_SINGLETONS 56
+#define UMFPACK_ROW_SINGLETONS 57
+#define UMFPACK_N2 58
+#define UMFPACK_S_SYMMETRIC 59
+
+/* estimates computed in UMFPACK_*symbolic: */
+#define UMFPACK_NUMERIC_SIZE_ESTIMATE 20    /* final size of Numeric->Memory */
+#define UMFPACK_PEAK_MEMORY_ESTIMATE 21            /* for symbolic & numeric */
+#define UMFPACK_FLOPS_ESTIMATE 22          /* flop count */
+#define UMFPACK_LNZ_ESTIMATE 23                    /* nz in L, incl. diagonal */
+#define UMFPACK_UNZ_ESTIMATE 24                    /* nz in U, incl. diagonal */
+#define UMFPACK_VARIABLE_INIT_ESTIMATE 25   /* initial size of Numeric->Memory*/
+#define UMFPACK_VARIABLE_PEAK_ESTIMATE 26   /* peak size of Numeric->Memory */
+#define UMFPACK_VARIABLE_FINAL_ESTIMATE 27  /* final size of Numeric->Memory */
+#define UMFPACK_MAX_FRONT_SIZE_ESTIMATE 28  /* max frontal matrix size */
+#define UMFPACK_MAX_FRONT_NROWS_ESTIMATE 29 /* max # rows in any front */
+#define UMFPACK_MAX_FRONT_NCOLS_ESTIMATE 30 /* max # columns in any front */
+
+/* exact values, (estimates shown above) computed in UMFPACK_numeric: */
+#define UMFPACK_NUMERIC_SIZE 40                    /* final size of Numeric->Memory */
+#define UMFPACK_PEAK_MEMORY 41             /* for symbolic & numeric */
+#define UMFPACK_FLOPS 42                   /* flop count */
+#define UMFPACK_LNZ 43                     /* nz in L, incl. diagonal */
+#define UMFPACK_UNZ 44                     /* nz in U, incl. diagonal */
+#define UMFPACK_VARIABLE_INIT 45           /* initial size of Numeric->Memory*/
+#define UMFPACK_VARIABLE_PEAK 46           /* peak size of Numeric->Memory */
+#define UMFPACK_VARIABLE_FINAL 47          /* final size of Numeric->Memory */
+#define UMFPACK_MAX_FRONT_SIZE 48          /* max frontal matrix size */
+#define UMFPACK_MAX_FRONT_NROWS 49         /* max # rows in any front */
+#define UMFPACK_MAX_FRONT_NCOLS 50         /* max # columns in any front */
+
+/* computed in UMFPACK_numeric: */
+#define UMFPACK_NUMERIC_DEFRAG 60          /* # of garbage collections */
+#define UMFPACK_NUMERIC_REALLOC 61         /* # of memory reallocations */
+#define UMFPACK_NUMERIC_COSTLY_REALLOC 62   /* # of costlly memory realloc's */
+#define UMFPACK_COMPRESSED_PATTERN 63      /* # of integers in LU pattern */
+#define UMFPACK_LU_ENTRIES 64              /* # of reals in LU factors */
+#define UMFPACK_NUMERIC_TIME 65                    /* numeric factorization time */
+#define UMFPACK_UDIAG_NZ 66                /* nz on diagonal of U */
+#define UMFPACK_RCOND 67                   /* est. reciprocal condition # */
+#define UMFPACK_WAS_SCALED 68              /* none, max row, or sum row */
+#define UMFPACK_RSMIN 69                   /* min (max row) or min (sum row) */
+#define UMFPACK_RSMAX 70                   /* max (max row) or max (sum row) */
+#define UMFPACK_UMIN 71                            /* min abs diagonal entry of U */
+#define UMFPACK_UMAX 72                            /* max abs diagonal entry of U */
+#define UMFPACK_ALLOC_INIT_USED 73         /* alloc_init parameter used */
+#define UMFPACK_FORCED_UPDATES 74          /* # of forced updates */
+#define UMFPACK_NUMERIC_WALLTIME 75        /* numeric wall clock time */
+#define UMFPACK_NOFF_DIAG 76               /* number of off-diagonal pivots */
+
+#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!) */
+
+#if 0
+/* No longer unused.  These parameters are now used for the new symmetric and
+ * 2-by-2 ordering strategies.  See 5, 12, 13, and 14, above. */
+#define UMFPACK_RELAXED_AMALGAMATION 5     /* unused (was in v4.0) */
+#define UMFPACK_PIVOT_OPTION 12                    /* unused (was in v3.2) */
+#define UMFPACK_RELAXED2_AMALGAMATION 13    /* unused (was in v4.0) */
+#define UMFPACK_RELAXED3_AMALGAMATION 14    /* unused (was in v4.0) */
+#endif
+
+/* -------------------------------------------------------------------------- */
+
+/* Control [UMFPACK_STRATEGY] is one of the following: */
+#define UMFPACK_STRATEGY_AUTO 0                /* use sym. or unsym. strategy */
+#define UMFPACK_STRATEGY_UNSYMMETRIC 1 /* COLAMD(A), coletree postorder,
+                                          not prefer diag*/
+#define UMFPACK_STRATEGY_2BY2 2                /* AMD(PA+PA'), no coletree postorder,
+                                          prefer diag(PA) where P is pseudo
+                                          max transversal */
+#define UMFPACK_STRATEGY_SYMMETRIC 3   /* AMD(A+A'), no coletree postorder,
+                                          prefer diagonal */
+
+/* Control [UMFPACK_SCALE] is one of the following: */
+#define UMFPACK_SCALE_NONE 0   /* no scaling */
+#define UMFPACK_SCALE_SUM 1    /* default: divide each row by sum (abs (row))*/
+#define UMFPACK_SCALE_MAX 2    /* divide each row by max (abs (row)) */
+
+/* -------------------------------------------------------------------------- */
+/* default values of Control: */
+/* -------------------------------------------------------------------------- */
+
+/* Note that the default block sized changed for Version 3.1 and following.
+ * In Version 4.1, the relaxed amalgamation parameters were removed.  These are
+ * now fixed internally (see umf_local_search.c), and cannot be changed.
+ * COLAMD aggressive absorption did not exist in v4.0.  In v4.1, it is in
+ * use by default (but can be turned off).  Aggressive absorption is used by
+ * default in AMD, also.
+ *
+ * Drop tolerance was added in V4.2.
+ */
+
+#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
+
+#if 0
+/* no longer unused: for unsymmetric strategy (were used in v4.0) */
+#define UMFPACK_DEFAULT_RELAXED_AMALGAMATION 0.25      /* unused */
+#define UMFPACK_DEFAULT_RELAXED2_AMALGAMATION 0.1      /* unused */
+#define UMFPACK_DEFAULT_RELAXED3_AMALGAMATION 0.125    /* unused */
+#endif
+
+/* default values of Control may change in future versions of UMFPACK. */
+
+/* -------------------------------------------------------------------------- */
+/* status codes */
+/* -------------------------------------------------------------------------- */
+
+#define UMFPACK_OK (0)
+
+/* status > 0 means a warning, but the method was successful anyway. */
+/* A Symbolic or Numeric object was still created. */
+#define UMFPACK_WARNING_singular_matrix (1)
+
+/* status < 0 means an error, and the method was not successful. */
+/* No Symbolic of Numeric object was created. */
+#define UMFPACK_ERROR_out_of_memory (-1)
+#define UMFPACK_ERROR_invalid_Numeric_object (-3)
+#define UMFPACK_ERROR_invalid_Symbolic_object (-4)
+#define UMFPACK_ERROR_argument_missing (-5)
+#define UMFPACK_ERROR_n_nonpositive (-6)
+#define UMFPACK_ERROR_invalid_matrix (-8)   /* replaces errors -[7:10,12,14] */
+#define UMFPACK_ERROR_different_pattern (-11)
+#define UMFPACK_ERROR_invalid_system (-13)
+#define UMFPACK_ERROR_invalid_permutation (-15)
+#define UMFPACK_ERROR_internal_error (-911)
+#define UMFPACK_ERROR_file_IO (-17)
+
+/* The following error codes are no longer used.  They are left in for
+ * historical reasons.  They appeared in Version 4.0.  Most of them are combined
+ * into the single UMFPACK_ERROR_invalid_matrix error code (-8).  The last one,
+ * UMFPACK_ERROR_problem_too_large, has been removed.  This error can no longer
+ * occur. */
+#define UMFPACK_ERROR_nz_negative (-7)                 /* unused */
+#define UMFPACK_ERROR_jumbled_matrix (-8)              /* unused */
+#define UMFPACK_ERROR_Ap0_nonzero (-9)                 /* unused */
+#define UMFPACK_ERROR_row_index_out_of_bounds (-10)    /* unused */
+#define UMFPACK_ERROR_col_length_negative (-12)                /* unused */
+#define UMFPACK_ERROR_invalid_triplet (-14)            /* unused */
+#define UMFPACK_ERROR_problem_too_large (-16)          /* unused */
+
+/* -------------------------------------------------------------------------- */
+/* solve codes */
+/* -------------------------------------------------------------------------- */
+
+/* Solve the system ( )x=b, where ( ) is defined below.  "t" refers to the */
+/* linear algebraic transpose (complex conjugate if A is complex), or the (') */
+/* operator in MATLAB.  "at" refers to the array transpose, or the (.') */
+/* operator in MATLAB. */
+
+#define UMFPACK_A      (0)     /* Ax=b    */
+#define UMFPACK_At     (1)     /* A'x=b   */
+#define UMFPACK_Aat    (2)     /* A.'x=b  */
+
+#define UMFPACK_Pt_L   (3)     /* P'Lx=b  */
+#define UMFPACK_L      (4)     /* Lx=b    */
+#define UMFPACK_Lt_P   (5)     /* L'Px=b  */
+#define UMFPACK_Lat_P  (6)     /* L.'Px=b */
+#define UMFPACK_Lt     (7)     /* L'x=b   */
+#define UMFPACK_Lat    (8)     /* L.'x=b  */
+
+#define UMFPACK_U_Qt   (9)     /* UQ'x=b  */
+#define UMFPACK_U      (10)    /* Ux=b    */
+#define UMFPACK_Q_Ut   (11)    /* QU'x=b  */
+#define UMFPACK_Q_Uat  (12)    /* QU.'x=b */
+#define UMFPACK_Ut     (13)    /* U'x=b   */
+#define UMFPACK_Uat    (14)    /* U.'x=b  */
+
+/* -------------------------------------------------------------------------- */
+
+/* Integer constants are used for status and solve codes instead of enum */
+/* to make it easier for a Fortran code to call UMFPACK. */
+
+#endif /* UMFPACK_H */
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_col_to_triplet.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_col_to_triplet.h
new file mode 100644 (file)
index 0000000..54cb722
--- /dev/null
@@ -0,0 +1,111 @@
+/* ========================================================================== */
+/* === umfpack_col_to_triplet =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_col_to_triplet
+(
+    int n_col,
+    const int Ap [ ],
+    int Tj [ ]
+) ;
+
+long umfpack_dl_col_to_triplet
+(
+    long n_col,
+    const long Ap [ ],
+    long Tj [ ]
+) ;
+
+int umfpack_zi_col_to_triplet
+(
+    int n_col,
+    const int Ap [ ],
+    int Tj [ ]
+) ;
+
+long umfpack_zl_col_to_triplet
+(
+    long n_col,
+    const long Ap [ ],
+    long Tj [ ]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    int n_col, *Tj, *Ap, status ;
+    status = umfpack_di_col_to_triplet (n_col, Ap, Tj) ;
+
+double long Syntax:
+
+    #include "umfpack.h"
+    long n_col, *Tj, *Ap, status ;
+    status = umfpack_dl_col_to_triplet (n_col, Ap, Tj) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    int n_col, *Tj, *Ap, status ;
+    status = umfpack_zi_col_to_triplet (n_col, Ap, Tj) ;
+
+complex long Syntax:
+
+    #include "umfpack.h"
+    long n_col, *Tj, *Ap, status ;
+    status = umfpack_zl_col_to_triplet (n_col, Ap, Tj) ;
+
+Purpose:
+
+    Converts a column-oriented matrix to a triplet form.  Only the column
+    pointers, Ap, are required, and only the column indices of the triplet form
+    are constructed.   This routine is the opposite of umfpack_*_triplet_to_col.
+    The matrix may be singular and/or rectangular.  Analogous to [i, Tj, x] =
+    find (A) in MATLAB, except that zero entries present in the column-form of
+    A are present in the output, and i and x are not created (those are just Ai
+    and Ax+Az*1i, respectively, for a column-form matrix A).
+
+Returns:
+
+    UMFPACK_OK if successful
+    UMFPACK_ERROR_argument_missing if Ap or Tj is missing
+    UMFPACK_ERROR_n_nonpositive if n_col <= 0
+    UMFPACK_ERROR_invalid_matrix if Ap [n_col] < 0, Ap [0] != 0, or
+       Ap [j] > Ap [j+1] for any j in the range 0 to n-1.
+    Unsorted columns and duplicate entries do not cause an error (these would
+    only be evident by examining Ai).  Empty rows and columns are OK.
+
+Arguments:
+
+    Int n_col ;                Input argument, not modified.
+
+       A is an n_row-by-n_col matrix.  Restriction: n_col > 0.
+       (n_row is not required)
+
+    Int Ap [n_col+1] ; Input argument, not modified.
+
+       The column pointers of the column-oriented form of the matrix.  See
+       umfpack_*_*symbolic for a description.  The number of entries in
+       the matrix is nz = Ap [n_col].  Restrictions on Ap are the same as those
+       for umfpack_*_transpose.  Ap [0] must be zero, nz must be >= 0, and
+       Ap [j] <= Ap [j+1] and Ap [j] <= Ap [n_col] must be true for all j in
+       the range 0 to n_col-1.  Empty columns are OK (that is, Ap [j] may equal
+       Ap [j+1] for any j in the range 0 to n_col-1).
+
+    Int Tj [nz] ;      Output argument.
+
+       Tj is an integer array of size nz on input, where nz = Ap [n_col].
+       Suppose the column-form of the matrix is held in Ap, Ai, Ax, and Az
+       (see umfpack_*_*symbolic for a description).  Then on output, the
+       triplet form of the same matrix is held in Ai (row indices), Tj (column
+       indices), and Ax (numerical values).  Note, however, that this routine
+       does not require Ai and Ax (or Az for the complex version) in order to
+       do the conversion.
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_defaults.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_defaults.h
new file mode 100644 (file)
index 0000000..ee61069
--- /dev/null
@@ -0,0 +1,75 @@
+/* ========================================================================== */
+/* === umfpack_defaults ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+void umfpack_di_defaults
+(
+    double Control [UMFPACK_CONTROL]
+) ;
+
+void umfpack_dl_defaults
+(
+    double Control [UMFPACK_CONTROL]
+) ;
+
+void umfpack_zi_defaults
+(
+    double Control [UMFPACK_CONTROL]
+) ;
+
+void umfpack_zl_defaults
+(
+    double Control [UMFPACK_CONTROL]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL] ;
+    umfpack_di_defaults (Control) ;
+
+double long Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL] ;
+    umfpack_dl_defaults (Control) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL] ;
+    umfpack_zi_defaults (Control) ;
+
+complex long Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL] ;
+    umfpack_zl_defaults (Control) ;
+
+Purpose:
+
+    Sets the default control parameter settings.
+
+    NOTE:  new control parameters have been added to the Control array for
+    Version 4.1.  These entries were unused in Version 4.0.  The default block
+    size for the BLAS has increased from 24 to 32.  Some rarely used control
+    parameters have been removed (those that controlled relaxed amalgamation).
+
+Arguments:
+
+    double Control [UMFPACK_CONTROL] ; Output argument.
+
+       Control is set to the default control parameter settings.  You can
+       then modify individual settings by changing specific entries in the
+       Control array.  If Control is a (double *) NULL pointer, then
+       umfpack_*_defaults returns silently (no error is generated, since
+       passing a NULL pointer for Control to any UMFPACK routine is valid).
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_free_numeric.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_free_numeric.h
new file mode 100644 (file)
index 0000000..e0b4ea7
--- /dev/null
@@ -0,0 +1,68 @@
+/* ========================================================================== */
+/* === umfpack_free_numeric ================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+void umfpack_di_free_numeric
+(
+    void **Numeric
+) ;
+
+void umfpack_dl_free_numeric
+(
+    void **Numeric
+) ;
+
+void umfpack_zi_free_numeric
+(
+    void **Numeric
+) ;
+
+void umfpack_zl_free_numeric
+(
+    void **Numeric
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    umfpack_di_free_numeric (&Numeric) ;
+
+double long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    umfpack_dl_free_numeric (&Numeric) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    umfpack_zi_free_numeric (&Numeric) ;
+
+complex long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    umfpack_zl_free_numeric (&Numeric) ;
+
+Purpose:
+
+    Deallocates the Numeric object and sets the Numeric handle to NULL.  This
+    routine is the only valid way of destroying the Numeric object.
+
+Arguments:
+
+    void **Numeric ;       Input argument, set to (void *) NULL on output.
+
+       Numeric points to a valid Numeric object, computed by umfpack_*_numeric.
+       No action is taken if Numeric is a (void *) NULL pointer.
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_free_symbolic.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_free_symbolic.h
new file mode 100644 (file)
index 0000000..103988a
--- /dev/null
@@ -0,0 +1,68 @@
+/* ========================================================================== */
+/* === umfpack_free_symbolic ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+void umfpack_di_free_symbolic
+(
+    void **Symbolic
+) ;
+
+void umfpack_dl_free_symbolic
+(
+    void **Symbolic
+) ;
+
+void umfpack_zi_free_symbolic
+(
+    void **Symbolic
+) ;
+
+void umfpack_zl_free_symbolic
+(
+    void **Symbolic
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    umfpack_di_free_symbolic (&Symbolic) ;
+
+double long Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    umfpack_dl_free_symbolic (&Symbolic) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    umfpack_zi_free_symbolic (&Symbolic) ;
+
+complex long Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    umfpack_zl_free_symbolic (&Symbolic) ;
+
+Purpose:
+
+    Deallocates the Symbolic object and sets the Symbolic handle to NULL.  This
+    routine is the only valid way of destroying the Symbolic object.
+
+Arguments:
+
+    void **Symbolic ;      Input argument, set to (void *) NULL on output.
+
+       Points to a valid Symbolic object computed by umfpack_*_symbolic.
+       No action is taken if Symbolic is a (void *) NULL pointer.
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_get_lunz.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_get_lunz.h
new file mode 100644 (file)
index 0000000..8f9d4b0
--- /dev/null
@@ -0,0 +1,134 @@
+/* ========================================================================== */
+/* === umfpack_get_lunz ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_get_lunz
+(
+    int *lnz,
+    int *unz,
+    int *n_row,
+    int *n_col,
+    int *nz_udiag,
+    void *Numeric
+) ;
+
+long umfpack_dl_get_lunz
+(
+    long *lnz,
+    long *unz,
+    long *n_row,
+    long *n_col,
+    long *nz_udiag,
+    void *Numeric
+) ;
+
+int umfpack_zi_get_lunz
+(
+    int *lnz,
+    int *unz,
+    int *n_row,
+    int *n_col,
+    int *nz_udiag,
+    void *Numeric
+) ;
+
+long umfpack_zl_get_lunz
+(
+    long *lnz,
+    long *unz,
+    long *n_row,
+    long *n_col,
+    long *nz_udiag,
+    void *Numeric
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    int status, lnz, unz, n_row, n_col ;
+    status = umfpack_di_get_lunz (&lnz, &unz, &n_row, &n_col, Numeric) ;
+
+double long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    long status, lnz, unz, n_row, n_col ;
+    status = umfpack_dl_get_lunz (&lnz, &unz, &n_row, &n_col, Numeric) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    int status, lnz, unz, n_row, n_col ;
+    status = umfpack_zi_get_lunz (&lnz, &unz, &n_row, &n_col, Numeric) ;
+
+complex long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    long status, lnz, unz, n_row, n_col ;
+    status = umfpack_zl_get_lunz (&lnz, &unz, &n_row, &n_col, Numeric) ;
+
+Purpose:
+
+    Determines the size and number of nonzeros in the LU factors held by the
+    Numeric object.  These are also the sizes of the output arrays required
+    by umfpack_*_get_numeric.
+
+    The matrix L is n_row -by- min(n_row,n_col), with lnz nonzeros, including
+    the entries on the unit diagonal of L.
+
+    The matrix U is min(n_row,n_col) -by- n_col, with unz nonzeros, including
+    nonzeros on the diagonal of U.
+
+Returns:
+
+    UMFPACK_OK if successful.
+    UMFPACK_ERROR_invalid_Numeric_object if Numeric is not a valid object.
+    UMFPACK_ERROR_argument_missing if any other argument is (Int *) NULL.
+
+Arguments:
+
+    Int *lnz ;         Output argument.
+
+       The number of nonzeros in L, including the diagonal (which is all
+       one's).  This value is the required size of the Lj and Lx arrays as
+       computed by umfpack_*_get_numeric.  The value of lnz is identical to
+       Info [UMFPACK_LNZ], if that value was returned by umfpack_*_numeric.
+
+    Int *unz ;         Output argument.
+
+       The number of nonzeros in U, including the diagonal.  This value is the
+       required size of the Ui and Ux arrays as computed by
+       umfpack_*_get_numeric.  The value of unz is identical to
+       Info [UMFPACK_UNZ], if that value was returned by umfpack_*_numeric.
+
+    Int *n_row ;       Output argument.
+    Int *n_col ;       Output argument.
+
+       The order of the L and U matrices.  L is n_row -by- min(n_row,n_col)
+       and U is min(n_row,n_col) -by- n_col.
+
+    Int *nz_udiag ;    Output argument.
+
+       The number of numerically nonzero values on the diagonal of U.  The
+       matrix is singular if nz_diag < min(n_row,n_col).  A divide-by-zero
+       will occur if nz_diag < n_row == n_col when solving a sparse system
+       involving the matrix U in umfpack_*_*solve.  The value of nz_udiag is
+       identical to Info [UMFPACK_UDIAG_NZ] if that value was returned by
+       umfpack_*_numeric.
+
+    void *Numeric ;    Input argument, not modified.
+
+       Numeric must point to a valid Numeric object, computed by
+       umfpack_*_numeric.
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_get_numeric.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_get_numeric.h
new file mode 100644 (file)
index 0000000..42001c4
--- /dev/null
@@ -0,0 +1,253 @@
+/* ========================================================================== */
+/* === umfpack_get_numeric ================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_get_numeric
+(
+    int Lp [ ],
+    int Lj [ ],
+    double Lx [ ],
+    int Up [ ],
+    int Ui [ ],
+    double Ux [ ],
+    int P [ ],
+    int Q [ ],
+    double Dx [ ],
+    int *do_recip,
+    double Rs [ ],
+    void *Numeric
+) ;
+
+long umfpack_dl_get_numeric
+(
+    long Lp [ ],
+    long Lj [ ],
+    double Lx [ ],
+    long Up [ ],
+    long Ui [ ],
+    double Ux [ ],
+    long P [ ],
+    long Q [ ],
+    double Dx [ ],
+    long *do_recip,
+    double Rs [ ],
+    void *Numeric
+) ;
+
+int umfpack_zi_get_numeric
+(
+    int Lp [ ],
+    int Lj [ ],
+    double Lx [ ], double Lz [ ],
+    int Up [ ],
+    int Ui [ ],
+    double Ux [ ], double Uz [ ],
+    int P [ ],
+    int Q [ ],
+    double Dx [ ], double Dz [ ],
+    int *do_recip,
+    double Rs [ ],
+    void *Numeric
+) ;
+
+long umfpack_zl_get_numeric
+(
+    long Lp [ ],
+    long Lj [ ],
+    double Lx [ ], double Lz [ ],
+    long Up [ ],
+    long Ui [ ],
+    double Ux [ ], double Uz [ ],
+    long P [ ],
+    long Q [ ],
+    double Dx [ ], double Dz [ ],
+    long *do_recip,
+    double Rs [ ],
+    void *Numeric
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    int *Lp, *Lj, *Up, *Ui, *P, *Q, status, do_recip ;
+    double *Lx, *Ux, *Dx, *Rs ;
+    status = umfpack_di_get_numeric (Lp, Lj, Lx, Up, Ui, Ux, P, Q, Dx,
+       &do_recip, Rs, Numeric) ;
+
+double long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    long *Lp, *Lj, *Up, *Ui, *P, *Q, status, do_recip ;
+    double *Lx, *Ux, *Dx, *Rs ;
+    status = umfpack_dl_get_numeric (Lp, Lj, Lx, Up, Ui, Ux, P, Q, Dx,
+       &do_recip, Rs, Numeric) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    int *Lp, *Lj, *Up, *Ui, *P, *Q, status, do_recip ;
+    double *Lx, *Lz, *Ux, *Uz, *Dx, *Dz, *Rs ;
+    status = umfpack_zi_get_numeric (Lp, Lj, Lx, Lz, Up, Ui, Ux, Uz, P, Q,
+       Dx, Dz, &do_recip, Rs, Numeric) ;
+
+complex long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    long *Lp, *Lj, *Up, *Ui, *P, *Q, status, do_recip ;
+    double *Lx, *Lz, *Ux, *Uz, *Dx, *Dz, *Rs ;
+    status = umfpack_zl_get_numeric (Lp, Lj, Lx, Lz, Up, Ui, Ux, Uz, P, Q,
+       Dx, Dz, &do_recip, Rs, Numeric) ;
+
+Purpose:
+
+    This routine copies the LU factors and permutation vectors from the Numeric
+    object into user-accessible arrays.  This routine is not needed to solve a
+    linear system.  Note that the output arrays Lp, Lj, Lx, Up, Ui, Ux, P, Q,
+    Dx, and Rs are not allocated by umfpack_*_get_numeric; they must exist on
+    input.  Similarly, Lz, Uz and Dz must exist on input for the complex
+    versions.
+
+    All output arguments are optional.  If any of them are NULL
+    on input, then that part of the LU factorization is not copied.  You can
+    use this routine to extract just the parts of the LU factorization that
+    you want.  For example, to retrieve just the column permutation Q, use:
+
+    #define noD (double *) NULL
+    #define noI (int *) NULL
+    status = umfpack_di_get_numeric (noI, noI, noD, noI, noI, noD, noI,
+       Q, noD, noI, noD, Numeric) ;
+
+Returns:
+
+    Returns UMFPACK_OK if successful.  Returns UMFPACK_ERROR_out_of_memory
+    if insufficient memory is available for the 2*max(n_row,n_col) integer
+    workspace that umfpack_*_get_numeric allocates to construct L and/or U.
+    Returns UMFPACK_ERROR_invalid_Numeric_object if the Numeric object provided
+    as input is invalid.
+
+Arguments:
+
+    Int Lp [n_row+1] ; Output argument.
+    Int Lj [lnz] ;     Output argument.
+    double Lx [lnz] ;  Output argument.
+    double Lz [lnz] ;  Output argument for complex versions.
+
+       The n_row-by-min(n_row,n_col) matrix L is returned in compressed-row
+       form.  The column indices of row i and corresponding numerical values
+       are in:
+
+           Lj [Lp [i] ... Lp [i+1]-1]
+           Lx [Lp [i] ... Lp [i+1]-1]  real part
+           Lz [Lp [i] ... Lp [i+1]-1]  imaginary part (complex versions)
+
+       respectively.  Each row is stored in sorted order, from low column
+       indices to higher.  The last entry in each row is the diagonal, which
+       is numerically equal to one.  The sizes of Lp, Lj, Lx, and Lz are
+       returned by umfpack_*_get_lunz.    If Lp, Lj, or Ux (or Uz for the
+       complex version) are not present, then the matrix L is not returned.
+       This is not an error condition.  The L matrix can be printed if n_row,
+       Lp, Lj, Lx (and Lz for the complex versions) are passed to
+       umfpack_*_report_matrix (using the "row" form).
+
+       Future complex version:  if Lx is present and Lz is NULL, then both real
+       and imaginary parts will be returned in Lx[0..2*lnz-1], with Lx[2*k]
+       and Lx[2*k+1] being the real and imaginary part of the kth entry.
+
+    Int Up [n_col+1] ; Output argument.
+    Int Ui [unz] ;     Output argument.
+    double Ux [unz] ;  Output argument.
+    double Uz [unz] ;  Output argument for complex versions.
+
+       The min(n_row,n_col)-by-n_col matrix U is returned in compressed-column
+       form.  The row indices of column j and corresponding numerical values
+       are in
+
+           Ui [Up [j] ... Up [j+1]-1]
+           Ux [Up [j] ... Up [j+1]-1]  real part
+           Uz [Up [j] ... Up [j+1]-1]  imaginary part (complex versions)
+
+       respectively.  Each column is stored in sorted order, from low row
+       indices to higher.  The last entry in each column is the diagonal
+       (assuming that it is nonzero).  The sizes of Up, Ui, Ux, and Uz are
+       returned by umfpack_*_get_lunz.  If Up, Ui, or Ux (or Uz for the complex
+       version) are not present, then the matrix U is not returned.  This is
+       not an error condition.  The U matrix can be printed if n_col, Up, Ui,
+       Ux (and Uz for the complex versions) are passed to
+       umfpack_*_report_matrix (using the "column" form).
+
+       Future complex version:  if Ux is present and Uz is NULL, then both real
+       and imaginary parts will be returned in Ux[0..2*unz-1], with Ux[2*k]
+       and Ux[2*k+1] being the real and imaginary part of the kth entry.
+
+    Int P [n_row] ;            Output argument.
+
+       The permutation vector P is defined as P [k] = i, where the original
+       row i of A is the kth pivot row in PAQ.  If you do not want the P vector
+       to be returned, simply pass (Int *) NULL for P.  This is not an error
+       condition.  You can print P and Q with umfpack_*_report_perm.
+
+    Int Q [n_col] ;            Output argument.
+
+       The permutation vector Q is defined as Q [k] = j, where the original
+       column j of A is the kth pivot column in PAQ.  If you not want the Q
+       vector to be returned, simply pass (Int *) NULL for Q.  This is not
+       an error condition.  Note that Q is not necessarily identical to
+       Qtree, the column pre-ordering held in the Symbolic object.  Refer to
+       the description of Qtree and Front_npivcol in umfpack_*_get_symbolic for
+       details.
+
+    double Dx [min(n_row,n_col)] ;     Output argument.
+    double Dz [min(n_row,n_col)] ;     Output argument for complex versions.
+
+       The diagonal of U is also returned in Dx and Dz.  You can extract the
+       diagonal of U without getting all of U by passing a non-NULL Dx (and
+       Dz for the complex version) and passing Up, Ui, and Ux as NULL.  Dx is
+       the real part of the diagonal, and Dz is the imaginary part.
+
+       Future complex version:  if Dx is present and Dz is NULL, then both real
+       and imaginary parts will be returned in Dx[0..2*min(n_row,n_col)-1],
+       with Dx[2*k] and Dx[2*k+1] being the real and imaginary part of the kth
+       entry.
+
+    Int *do_recip ;            Output argument.
+
+       If do_recip is returned as zero (false), then the scale factors Rs [i]
+       are to be used by multiplying row i by Rs [i].  Otherwise, the entries
+       in row i are to be divided by Rs [i].
+
+       If UMFPACK has been compiled with gcc, or for MATLAB as either a
+       built-in routine or as a mexFunction, then the NRECIPROCAL flag is
+       set, and do_recip will always be zero (false).
+
+       NOTE: this argument is new to version 4.1.
+
+    double Rs [n_row] ;                Output argument.
+
+       The row scale factors are returned in Rs [0..n_row-1].  Row i of A is
+       scaled by dividing or multiplying its values by Rs [i].  If default
+       scaling is in use, Rs [i] is the sum of the absolute values of row i
+       (or its reciprocal).  If max row scaling is in use, then Rs [i] is the
+       maximum absolute value in row i (or its reciprocal).
+       Otherwise, Rs [i] = 1.  If row i is all zero, Rs [i] = 1 as well.  For
+       the complex version, an approximate absolute value is used
+       (|x_real|+|x_imag|).
+
+       NOTE: this argument is new to version 4.1.
+
+    void *Numeric ;    Input argument, not modified.
+
+       Numeric must point to a valid Numeric object, computed by
+       umfpack_*_numeric.
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_get_symbolic.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_get_symbolic.h
new file mode 100644 (file)
index 0000000..5c48418
--- /dev/null
@@ -0,0 +1,342 @@
+/* ========================================================================== */
+/* === umfpack_get_symbolic ================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_get_symbolic
+(
+    int *n_row,
+    int *n_col,
+    int *n1,
+    int *nz,
+    int *nfr,
+    int *nchains,
+    int P [ ],
+    int Q [ ],
+    int Front_npivcol [ ],
+    int Front_parent [ ],
+    int Front_1strow [ ],
+    int Front_leftmostdesc [ ],
+    int Chain_start [ ],
+    int Chain_maxrows [ ],
+    int Chain_maxcols [ ],
+    void *Symbolic
+) ;
+
+long umfpack_dl_get_symbolic
+(
+    long *n_row,
+    long *n_col,
+    long *n1,
+    long *nz,
+    long *nfr,
+    long *nchains,
+    long P [ ],
+    long Q [ ],
+    long Front_npivcol [ ],
+    long Front_parent [ ],
+    long Front_1strow [ ],
+    long Front_leftmostdesc [ ],
+    long Chain_start [ ],
+    long Chain_maxrows [ ],
+    long Chain_maxcols [ ],
+    void *Symbolic
+) ;
+
+int umfpack_zi_get_symbolic
+(
+    int *n_row,
+    int *n_col,
+    int *n1,
+    int *nz,
+    int *nfr,
+    int *nchains,
+    int P [ ],
+    int Q [ ],
+    int Front_npivcol [ ],
+    int Front_parent [ ],
+    int Front_1strow [ ],
+    int Front_leftmostdesc [ ],
+    int Chain_start [ ],
+    int Chain_maxrows [ ],
+    int Chain_maxcols [ ],
+    void *Symbolic
+) ;
+
+long umfpack_zl_get_symbolic
+(
+    long *n_row,
+    long *n_col,
+    long *n1,
+    long *nz,
+    long *nfr,
+    long *nchains,
+    long P [ ],
+    long Q [ ],
+    long Front_npivcol [ ],
+    long Front_parent [ ],
+    long Front_1strow [ ],
+    long Front_leftmostdesc [ ],
+    long Chain_start [ ],
+    long Chain_maxrows [ ],
+    long Chain_maxcols [ ],
+    void *Symbolic
+) ;
+
+/*
+
+double int Syntax:
+
+    #include "umfpack.h"
+    int status, n_row, n_col, nz, nfr, nchains, *P, *Q,
+       *Front_npivcol, *Front_parent, *Front_1strow, *Front_leftmostdesc,
+       *Chain_start, *Chain_maxrows, *Chain_maxcols ;
+    void *Symbolic ;
+    status = umfpack_di_get_symbolic (&n_row, &n_col, &nz, &nfr, &nchains,
+       P, Q, Front_npivcol, Front_parent, Front_1strow,
+       Front_leftmostdesc, Chain_start, Chain_maxrows, Chain_maxcols,
+       Symbolic) ;
+
+double long Syntax:
+
+    #include "umfpack.h"
+    long status, n_row, n_col, nz, nfr, nchains, *P, *Q,
+       *Front_npivcol, *Front_parent, *Front_1strow, *Front_leftmostdesc,
+       *Chain_start, *Chain_maxrows, *Chain_maxcols ;
+    void *Symbolic ;
+    status = umfpack_dl_get_symbolic (&n_row, &n_col, &nz, &nfr, &nchains,
+       P, Q, Front_npivcol, Front_parent, Front_1strow,
+       Front_leftmostdesc, Chain_start, Chain_maxrows, Chain_maxcols,
+       Symbolic) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    int status, n_row, n_col, nz, nfr, nchains, *P, *Q,
+       *Front_npivcol, *Front_parent, *Front_1strow, *Front_leftmostdesc,
+       *Chain_start, *Chain_maxrows, *Chain_maxcols ;
+    void *Symbolic ;
+    status = umfpack_zi_get_symbolic (&n_row, &n_col, &nz, &nfr, &nchains,
+       P, Q, Front_npivcol, Front_parent, Front_1strow,
+       Front_leftmostdesc, Chain_start, Chain_maxrows, Chain_maxcols,
+       Symbolic) ;
+
+complex long Syntax:
+
+    #include "umfpack.h"
+    long status, n_row, n_col, nz, nfr, nchains, *P, *Q,
+       *Front_npivcol, *Front_parent, *Front_1strow, *Front_leftmostdesc,
+       *Chain_start, *Chain_maxrows, *Chain_maxcols ;
+    void *Symbolic ;
+    status = umfpack_zl_get_symbolic (&n_row, &n_col, &nz, &nfr, &nchains,
+       P, Q, Front_npivcol, Front_parent, Front_1strow,
+       Front_leftmostdesc, Chain_start, Chain_maxrows, Chain_maxcols,
+       Symbolic) ;
+
+Purpose:
+
+    Copies the contents of the Symbolic object into simple integer arrays
+    accessible to the user.  This routine is not needed to factorize and/or
+    solve a sparse linear system using UMFPACK.  Note that the output arrays
+    P, Q, Front_npivcol, Front_parent, Front_1strow, Front_leftmostdesc,
+    Chain_start, Chain_maxrows, and Chain_maxcols are not allocated by
+    umfpack_*_get_symbolic; they must exist on input.
+
+    All output arguments are optional.  If any of them are NULL
+    on input, then that part of the symbolic analysis is not copied.  You can
+    use this routine to extract just the parts of the symbolic analysis that
+    you want.  For example, to retrieve just the column permutation Q, use:
+
+    #define noI (int *) NULL
+    status = umfpack_di_get_symbolic (noI, noI, noI, noI, noI, noI, noI,
+           Q, noI, noI, noI, noI, noI, noI, noI, Symbolic) ;
+
+    The only required argument the last one, the pointer to the Symbolic object.
+
+    The Symbolic object is small.  Its size for an n-by-n square matrix varies
+    from 4*n to 13*n, depending on the matrix.  The object holds the initial
+    column permutation, the supernodal column elimination tree, and information
+    about each frontal matrix.  You can print it with umfpack_*_report_symbolic.
+
+Returns:
+
+    Returns UMFPACK_OK if successful, UMFPACK_ERROR_invalid_Symbolic_object
+    if Symbolic is an invalid object.
+
+Arguments:
+
+    Int *n_row ;       Output argument.
+    Int *n_col ;       Output argument.
+
+       The dimensions of the matrix A analyzed by the call to
+       umfpack_*_symbolic that generated the Symbolic object.
+
+    Int *n1 ;          Output argument.
+
+       The number of pivots with zero Markowitz cost (they have just one entry
+       in the pivot row, or the pivot column, or both).  These appear first in
+       the output permutations P and Q.
+
+       NOTE: this argument is new to version 4.1.
+
+    Int *nz ;          Output argument.
+
+       The number of nonzeros in A.
+
+    Int *nfr ; Output argument.
+
+       The number of frontal matrices that will be used by umfpack_*_numeric
+       to factorize the matrix A.  It is in the range 0 to n_col.
+
+    Int *nchains ;     Output argument.
+
+       The frontal matrices are related to one another by the supernodal
+       column elimination tree.  Each node in this tree is one frontal matrix.
+       The tree is partitioned into a set of disjoint paths, and a frontal
+       matrix chain is one path in this tree.  Each chain is factorized using
+       a unifrontal technique, with a single working array that holds each
+       frontal matrix in the chain, one at a time.  nchains is in the range
+       0 to nfr.
+
+    Int P [n_row] ;    Output argument.
+
+       The initial row permutation.  If P [k] = i, then this means that
+       row i is the kth row in the pre-ordered matrix.  In general, this P is
+       not the same as the final row permutation computed by umfpack_*_numeric.
+
+       For the unsymmetric strategy, P defines the row-merge order.  Let j be
+       the column index of the leftmost nonzero entry in row i of A*Q.  Then
+       P defines a sort of the rows according to this value.  A row can appear
+       earlier in this ordering if it is aggressively absorbed before it can
+       become a pivot row.  If P [k] = i, row i typically will not be the kth
+       pivot row.
+
+       For the symmetric strategy, P = Q.  For the 2-by-2 strategy, P is the
+       row permutation that places large entries on the diagonal of P*A*Q.
+       If no pivoting occurs during numerical factorization, P [k] = i also
+       defines the final permutation of umfpack_*_numeric, for either the
+       symmetric or 2-by-2 strategies.
+
+    Int Q [n_col] ;    Output argument.
+
+       The initial column permutation.  If Q [k] = j, then this means that
+       column j is the kth pivot column in the pre-ordered matrix.  Q is
+       not necessarily the same as the final column permutation Q, computed by
+       umfpack_*_numeric.  The numeric factorization may reorder the pivot
+       columns within each frontal matrix to reduce fill-in.  If the matrix is
+       structurally singular, and if the symmetric or 2-by-2 strategies or
+       used (or if Control [UMFPACK_FIXQ] > 0), then this Q will be the same
+       as the final column permutation computed in umfpack_*_numeric.
+
+    Int Front_npivcol [n_col+1] ;      Output argument.
+
+       This array should be of size at least n_col+1, in order to guarantee
+       that it will be large enough to hold the output.  Only the first nfr+1
+       entries are used, however.
+
+       The kth frontal matrix holds Front_npivcol [k] pivot columns.  Thus, the
+       first frontal matrix, front 0, is used to factorize the first
+       Front_npivcol [0] columns; these correspond to the original columns
+       Q [0] through Q [Front_npivcol [0]-1].  The next frontal matrix
+       is used to factorize the next Front_npivcol [1] columns, which are thus
+       the original columns Q [Front_npivcol [0]] through
+       Q [Front_npivcol [0] + Front_npivcol [1] - 1], and so on.  Columns
+       with no entries at all are put in a placeholder "front",
+       Front_npivcol [nfr].  The sum of Front_npivcol [0..nfr] is equal to
+       n_col.
+
+       Any modifications that umfpack_*_numeric makes to the initial column
+       permutation are constrained to within each frontal matrix.  Thus, for
+       the first frontal matrix, Q [0] through Q [Front_npivcol [0]-1] is some
+       permutation of the columns Q [0] through
+       Q [Front_npivcol [0]-1].  For second frontal matrix,
+       Q [Front_npivcol [0]] through Q [Front_npivcol [0] + Front_npivcol[1]-1]
+       is some permutation of the same portion of Q, and so on.  All pivot
+       columns are numerically factorized within the frontal matrix originally
+       determined by the symbolic factorization; there is no delayed pivoting
+       across frontal matrices.
+
+    Int Front_parent [n_col+1] ;       Output argument.
+
+       This array should be of size at least n_col+1, in order to guarantee
+       that it will be large enough to hold the output.  Only the first nfr+1
+       entries are used, however.
+
+       Front_parent [0..nfr] holds the supernodal column elimination tree
+       (including the placeholder front nfr, which may be empty).  Each node in
+       the tree corresponds to a single frontal matrix.  The parent of node f
+       is Front_parent [f].
+
+    Int Front_1strow [n_col+1] ;       Output argument.
+
+       This array should be of size at least n_col+1, in order to guarantee
+       that it will be large enough to hold the output.  Only the first nfr+1
+       entries are used, however.
+
+       Front_1strow [k] is the row index of the first row in A (P,Q)
+       whose leftmost entry is in a pivot column for the kth front.  This is
+       necessary only to properly factorize singular matrices.  It is new to
+       Version 4.0.  Rows in the range Front_1strow [k] to
+       Front_1strow [k+1]-1 first become pivot row candidates at the kth front.
+       Any rows not eliminated in the kth front may be selected as pivot rows
+       in the parent of k (Front_parent [k]) and so on up the tree.
+
+    Int Front_leftmostdesc [n_col+1] ; Output argument.
+
+       This array should be of size at least n_col+1, in order to guarantee
+       that it will be large enough to hold the output.  Only the first nfr+1
+       entries are used, however.
+
+       Front_leftmostdesc [k] is the leftmost descendant of front k, or k
+       if the front has no children in the tree.  Since the rows and columns
+       (P and Q) have been post-ordered via a depth-first-search of
+       the tree, rows in the range Front_1strow [Front_leftmostdesc [k]] to
+       Front_1strow [k+1]-1 form the entire set of candidate pivot rows for
+       the kth front (some of these will typically have already been selected
+       by fronts in the range Front_leftmostdesc [k] to front k-1, before
+       the factorization reaches front k).
+
+    Chain_start [n_col+1] ;    Output argument.
+
+       This array should be of size at least n_col+1, in order to guarantee
+       that it will be large enough to hold the output.  Only the first
+       nchains+1 entries are used, however.
+
+       The kth frontal matrix chain consists of frontal matrices Chain_start[k]
+       through Chain_start [k+1]-1.  Thus, Chain_start [0] is always 0, and
+       Chain_start [nchains] is the total number of frontal matrices, nfr.  For
+       two adjacent fronts f and f+1 within a single chain, f+1 is always the
+       parent of f (that is, Front_parent [f] = f+1).
+
+    Int Chain_maxrows [n_col+1] ;      Output argument.
+    Int Chain_maxcols [n_col+1] ;      Output argument.
+
+       These arrays should be of size at least n_col+1, in order to guarantee
+       that they will be large enough to hold the output.  Only the first
+       nchains entries are used, however.
+
+       The kth frontal matrix chain requires a single working array of
+       dimension Chain_maxrows [k] by Chain_maxcols [k], for the unifrontal
+       technique that factorizes the frontal matrix chain.  Since the symbolic
+       factorization only provides an upper bound on the size of each frontal
+       matrix, not all of the working array is necessarily used during the
+       numerical factorization.
+
+       Note that the upper bound on the number of rows and columns of each
+       frontal matrix is computed by umfpack_*_symbolic, but all that is
+       required by umfpack_*_numeric is the maximum of these two sets of
+       values for each frontal matrix chain.  Thus, the size of each
+       individual frontal matrix is not preserved in the Symbolic object.
+
+    void *Symbolic ;                   Input argument, not modified.
+
+       The Symbolic object, which holds the symbolic factorization computed by
+       umfpack_*_symbolic.  The Symbolic object is not modified by
+       umfpack_*_get_symbolic.
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_load_numeric.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_load_numeric.h
new file mode 100644 (file)
index 0000000..7d1f3b3
--- /dev/null
@@ -0,0 +1,96 @@
+/* ========================================================================== */
+/* === umfpack_load_numeric ================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_load_numeric
+(
+    void **Numeric,
+    char *filename
+) ;
+
+long umfpack_dl_load_numeric
+(
+    void **Numeric,
+    char *filename
+) ;
+
+int umfpack_zi_load_numeric
+(
+    void **Numeric,
+    char *filename
+) ;
+
+long umfpack_zl_load_numeric
+(
+    void **Numeric,
+    char *filename
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    int status ;
+    char *filename ;
+    void *Numeric ;
+    status = umfpack_di_load_numeric (&Numeric, filename) ;
+
+double long Syntax:
+
+    #include "umfpack.h"
+    long status ;
+    char *filename ;
+    void *Numeric ;
+    status = umfpack_dl_load_numeric (&Numeric, filename) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    int status ;
+    char *filename ;
+    void *Numeric ;
+    status = umfpack_zi_load_numeric (&Numeric, filename) ;
+
+complex long Syntax:
+
+    #include "umfpack.h"
+    long status ;
+    char *filename ;
+    void *Numeric ;
+    status = umfpack_zl_load_numeric (&Numeric, filename) ;
+
+Purpose:
+
+    Loads a Numeric object from a file created by umfpack_*_save_numeric.  The
+    Numeric handle passed to this routine is overwritten with the new object.
+    If that object exists prior to calling this routine, a memory leak will
+    occur.  The contents of Numeric are ignored on input.
+
+Returns:
+
+    UMFPACK_OK if successful.
+    UMFPACK_ERROR_out_of_memory if not enough memory is available.
+    UMFPACK_ERROR_file_IO if an I/O error occurred.
+
+Arguments:
+
+    void **Numeric ;       Output argument.
+
+       **Numeric is the address of a (void *) pointer variable in the user's
+       calling routine (see Syntax, above).  On input, the contents of this
+       variable are not defined.  On output, this variable holds a (void *)
+       pointer to the Numeric object (if successful), or (void *) NULL if
+       a failure occurred.
+
+    char *filename ;       Input argument, not modified.
+
+       A string that contains the filename from which to read the Numeric
+       object.
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_load_symbolic.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_load_symbolic.h
new file mode 100644 (file)
index 0000000..69ece02
--- /dev/null
@@ -0,0 +1,96 @@
+/* ========================================================================== */
+/* === umfpack_load_symbolic ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_load_symbolic
+(
+    void **Symbolic,
+    char *filename
+) ;
+
+long umfpack_dl_load_symbolic
+(
+    void **Symbolic,
+    char *filename
+) ;
+
+int umfpack_zi_load_symbolic
+(
+    void **Symbolic,
+    char *filename
+) ;
+
+long umfpack_zl_load_symbolic
+(
+    void **Symbolic,
+    char *filename
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    int status ;
+    char *filename ;
+    void *Symbolic ;
+    status = umfpack_di_load_symbolic (&Symbolic, filename) ;
+
+double long Syntax:
+
+    #include "umfpack.h"
+    long status ;
+    char *filename ;
+    void *Symbolic ;
+    status = umfpack_dl_load_symbolic (&Symbolic, filename) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    int status ;
+    char *filename ;
+    void *Symbolic ;
+    status = umfpack_zi_load_symbolic (&Symbolic, filename) ;
+
+complex long Syntax:
+
+    #include "umfpack.h"
+    long status ;
+    char *filename ;
+    void *Symbolic ;
+    status = umfpack_zl_load_symbolic (&Symbolic, filename) ;
+
+Purpose:
+
+    Loads a Symbolic object from a file created by umfpack_*_save_symbolic. The
+    Symbolic handle passed to this routine is overwritten with the new object.
+    If that object exists prior to calling this routine, a memory leak will
+    occur.  The contents of Symbolic are ignored on input.
+
+Returns:
+
+    UMFPACK_OK if successful.
+    UMFPACK_ERROR_out_of_memory if not enough memory is available.
+    UMFPACK_ERROR_file_IO if an I/O error occurred.
+
+Arguments:
+
+    void **Symbolic ;      Output argument.
+
+       **Symbolic is the address of a (void *) pointer variable in the user's
+       calling routine (see Syntax, above).  On input, the contents of this
+       variable are not defined.  On output, this variable holds a (void *)
+       pointer to the Symbolic object (if successful), or (void *) NULL if
+       a failure occurred.
+
+    char *filename ;       Input argument, not modified.
+
+       A string that contains the filename from which to read the Symbolic
+       object.
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_numeric.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_numeric.h
new file mode 100644 (file)
index 0000000..a57fd0d
--- /dev/null
@@ -0,0 +1,552 @@
+/* ========================================================================== */
+/* === umfpack_numeric ====================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_numeric
+(
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ],
+    void *Symbolic,
+    void **Numeric,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+long umfpack_dl_numeric
+(
+    const long Ap [ ],
+    const long Ai [ ],
+    const double Ax [ ],
+    void *Symbolic,
+    void **Numeric,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+int umfpack_zi_numeric
+(
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ], const double Az [ ],
+    void *Symbolic,
+    void **Numeric,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+long umfpack_zl_numeric
+(
+    const long Ap [ ],
+    const long Ai [ ],
+    const double Ax [ ], const double Az [ ],
+    void *Symbolic,
+    void **Numeric,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic, *Numeric ;
+    int *Ap, *Ai, status ;
+    double *Ax, Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ;
+    status = umfpack_di_numeric (Ap, Ai, Ax, Symbolic, &Numeric, Control, Info);
+
+double long Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic, *Numeric ;
+    long *Ap, *Ai, status ;
+    double *Ax, Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ;
+    status = umfpack_dl_numeric (Ap, Ai, Ax, Symbolic, &Numeric, Control, Info);
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic, *Numeric ;
+    int *Ap, *Ai, status ;
+    double *Ax, *Az, Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ;
+    status = umfpack_zi_numeric (Ap, Ai, Ax, Az, Symbolic, &Numeric,
+       Control, Info) ;
+
+complex long Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic, *Numeric ;
+    long *Ap, *Ai, status ;
+    double *Ax, *Az, Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ;
+    status = umfpack_zl_numeric (Ap, Ai, Ax, Symbolic, &Numeric,
+       Control, Info) ;
+
+Purpose:
+
+    Given a sparse matrix A in column-oriented form, and a symbolic analysis
+    computed by umfpack_*_*symbolic, the umfpack_*_numeric routine performs the
+    numerical factorization, PAQ=LU, PRAQ=LU, or P(R\A)Q=LU, where P and Q are
+    permutation matrices (represented as permutation vectors), R is the row
+    scaling, L is unit-lower triangular, and U is upper triangular.  This is
+    required before the system Ax=b (or other related linear systems) can be
+    solved.  umfpack_*_numeric can be called multiple times for each call to
+    umfpack_*_*symbolic, to factorize a sequence of matrices with identical
+    nonzero pattern.  Simply compute the Symbolic object once, with
+    umfpack_*_*symbolic, and reuse it for subsequent matrices.  This routine
+    safely detects if the pattern changes, and sets an appropriate error code.
+
+Returns:
+
+    The status code is returned.  See Info [UMFPACK_STATUS], below.
+
+Arguments:
+
+    Int Ap [n_col+1] ; Input argument, not modified.
+
+       This must be identical to the Ap array passed to umfpack_*_*symbolic.
+       The value of n_col is what was passed to umfpack_*_*symbolic (this is
+       held in the Symbolic object).
+
+    Int Ai [nz] ;      Input argument, not modified, of size nz = Ap [n_col].
+
+       This must be identical to the Ai array passed to umfpack_*_*symbolic.
+
+    double Ax [nz] ;   Input argument, not modified, of size nz = Ap [n_col].
+
+       The numerical values of the sparse matrix A.  The nonzero pattern (row
+       indices) for column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)], and
+       the corresponding numerical values are stored in
+       Ax [(Ap [j]) ... (Ap [j+1]-1)].
+
+    double Az [nz] ;   Input argument, not modified, for complex versions.
+
+       For the complex versions, this holds the imaginary part of A.  The
+       imaginary part of column j is held in Az [(Ap [j]) ... (Ap [j+1]-1)].
+
+       Future complex version:  if Ax is present and Az is NULL, then both real
+       and imaginary parts will be contained in Ax[0..2*nz-1], with Ax[2*k]
+       and Ax[2*k+1] being the real and imaginary part of the kth entry.
+
+    void *Symbolic ;   Input argument, not modified.
+
+       The Symbolic object, which holds the symbolic factorization computed by
+       umfpack_*_*symbolic.  The Symbolic object is not modified by
+       umfpack_*_numeric.
+
+    void **Numeric ;   Output argument.
+
+       **Numeric is the address of a (void *) pointer variable in the user's
+       calling routine (see Syntax, above).  On input, the contents of this
+       variable are not defined.  On output, this variable holds a (void *)
+       pointer to the Numeric object (if successful), or (void *) NULL if
+       a failure occurred.
+
+    double Control [UMFPACK_CONTROL] ;   Input argument, not modified.
+
+       If a (double *) NULL pointer is passed, then the default control
+       settings are used.  Otherwise, the settings are determined from the
+       Control array.  See umfpack_*_defaults on how to fill the Control
+       array with the default settings.  If Control contains NaN's, the
+       defaults are used.  The following Control parameters are used:
+
+       Control [UMFPACK_PIVOT_TOLERANCE]:  relative pivot tolerance for
+           threshold partial pivoting with row interchanges.  In any given
+           column, an entry is numerically acceptable if its absolute value is
+           greater than or equal to Control [UMFPACK_PIVOT_TOLERANCE] times
+           the largest absolute value in the column.  A value of 1.0 gives true
+           partial pivoting.  If less than or equal to zero, then any nonzero
+           entry is numerically acceptable as a pivot (this is changed from
+           Version 4.0).  Default: 0.1.
+
+           Smaller values tend to lead to sparser LU factors, but the solution
+           to the linear system can become inaccurate.  Larger values can lead
+           to a more accurate solution (but not always), and usually an
+           increase in the total work.
+
+           For complex matrices, a cheap approximate of the absolute value
+           is used for the threshold partial pivoting test (|a_real| + |a_imag|
+           instead of the more expensive-to-compute exact absolute value
+           sqrt (a_real^2 + a_imag^2)).
+
+       Control [UMFPACK_SYM_PIVOT_TOLERANCE]:  This parameter is new to V4.1.
+           If diagonal pivoting is attempted (the symmetric or symmetric-2by2
+           strategies are used) then this parameter is used to control when the
+           diagonal entry is selected in a given pivot column.  The absolute
+           value of the entry must be >= Control [UMFPACK_SYM_PIVOT_TOLERANCE]
+           times the largest absolute value in the column.  A value of zero
+           will ensure that no off-diagonal pivoting is performed, except that
+           zero diagonal entries are not selected if there are any off-diagonal
+           nonzero entries.
+
+           If an off-diagonal pivot is selected, an attempt is made to restore
+           symmetry later on.  Suppose A (i,j) is selected, where i != j.
+           If column i has not yet been selected as a pivot column, then
+           the entry A (j,i) is redefined as a "diagonal" entry, except that
+           the tighter tolerance (Control [UMFPACK_PIVOT_TOLERANCE]) is
+           applied.  This strategy has an effect similar to 2-by-2 pivoting
+           for symmetric indefinite matrices.  If a 2-by-2 block pivot with
+           nonzero structure
+
+                      i j
+                   i: 0 x
+                   j: x 0
+
+           is selected in a symmetric indefinite factorization method, the
+           2-by-2 block is inverted and a rank-2 update is applied.  In
+           UMFPACK, this 2-by-2 block would be reordered as
+
+                      j i
+                   i: x 0
+                   j: 0 x
+
+           In both cases, the symmetry of the Schur complement is preserved.
+
+       Control [UMFPACK_SCALE]:  This parameter is new to V4.1.  Version 4.0
+           did not scale the matrix.  Note that the user's input matrix is
+           never modified, only an internal copy is scaled.
+
+           There are three valid settings for this parameter.  If any other
+           value is provided, the default is used.
+
+           UMFPACK_SCALE_NONE:  no scaling is performed.
+
+           UMFPACK_SCALE_SUM:  each row of the input matrix A is divided by
+               the sum of the absolute values of the entries in that row.
+               The scaled matrix has an infinity norm of 1.
+
+           UMFPACK_SCALE_MAX:  each row of the input matrix A is divided by
+               the maximum the absolute values of the entries in that row.
+               In the scaled matrix the largest entry in each row has
+               a magnitude exactly equal to 1.
+
+           Note that for complex matrices, a cheap approximate absolute value
+           is used, |a_real| + |a_imag|, instead of the exact absolute value
+           sqrt ((a_real)^2 + (a_imag)^2).
+
+           Scaling is very important for the "symmetric" strategy when
+           diagonal pivoting is attempted.  It also improves the performance
+           of the "unsymmetric" strategy.
+
+           Default: UMFPACK_SCALE_SUM.
+
+       Control [UMFPACK_ALLOC_INIT]:  This parameter has changed in V4.1.
+
+           When umfpack_*_numeric starts, it allocates memory for the Numeric
+           object.  Part of this is of fixed size (approximately n double's +
+           12*n integers).  The remainder is of variable size, which grows to
+           hold the LU factors and the frontal matrices created during
+           factorization.  A estimate of the upper bound is computed by
+           umfpack_*_*symbolic, and returned by umfpack_*_*symbolic in
+           Info [UMFPACK_VARIABLE_PEAK_ESTIMATE] (in Units).
+
+           If Control [UMFPACK_ALLOC_INIT] is >= 0, umfpack_*_numeric initially
+           allocates space for the variable-sized part equal to this estimate
+           times Control [UMFPACK_ALLOC_INIT].  Typically, for matrices for
+           which the "unsymmetric" strategy applies, umfpack_*_numeric needs
+           only about half the estimated memory space, so a setting of 0.5 or
+           0.6 often provides enough memory for umfpack_*_numeric to factorize
+           the matrix with no subsequent increases in the size of this block.
+
+           If the matrix is ordered via AMD, then this non-negative parameter
+           is ignored.  The initial allocation ratio computed automatically,
+           as 1.2 * (nz + Info [UMFPACK_SYMMETRIC_LUNZ]) /
+           (Info [UMFPACK_LNZ_ESTIMATE] + Info [UMFPACK_UNZ_ESTIMATE] -
+           min (n_row, n_col)).
+
+           If Control [UMFPACK_ALLOC_INIT] is negative, then umfpack_*_numeric
+           allocates a space with initial size (in Units) equal to
+           (-Control [UMFPACK_ALLOC_INIT]).
+
+           Regardless of the value of this parameter, a space equal to or
+           greater than the the bare minimum amount of memory needed to start
+           the factorization is always initially allocated.  The bare initial
+           memory required is returned by umfpack_*_*symbolic in
+           Info [UMFPACK_VARIABLE_INIT_ESTIMATE] (an exact value, not an
+           estimate).
+
+           If the variable-size part of the Numeric object is found to be too
+           small sometime after numerical factorization has started, the memory
+           is increased in size by a factor of 1.2.   If this fails, the
+           request is reduced by a factor of 0.95 until it succeeds, or until
+           it determines that no increase in size is possible.  Garbage
+           collection then occurs.
+
+           The strategy of attempting to "malloc" a working space, and
+           re-trying with a smaller space, may not work under MATLAB, since
+           mxMalloc aborts the mexFunction if it fails.  The built-in umfpack
+           routine (version 4.0) in MATLAB 6.5 uses utMalloc instead, which
+           avoids this problem.  As a mexFunction, utMalloc is used unless
+           -DNUTIL is defined at compile time.  The utMalloc routine, and
+           utFree and utRealloc, are not documented.  If the mexFunction
+           doesn't work, then compile it with -DNUTIL instead.
+
+           If you are using the umfpack mexFunction, decrease the magnitude of
+           Control [UMFPACK_ALLOC_INIT] if you run out of memory in MATLAB.
+
+           Default initial allocation size: 0.7.  Thus, with the default
+           control settings and the "unsymmetric" strategy, the upper-bound is
+           reached after two reallocations (0.7 * 1.2 * 1.2 = 1.008).
+
+           Changing this parameter has little effect on fill-in or operation
+           count.  It has a small impact on run-time (the extra time required
+           to do the garbage collection and memory reallocation).
+
+       Control [UMFPACK_FRONT_ALLOC_INIT]:  This parameter is new to V4.1.
+
+           When UMFPACK starts the factorization of each "chain" of frontal
+           matrices, it allocates a working array to hold the frontal matrices
+           as they are factorized.  The symbolic factorization computes the
+           size of the largest possible frontal matrix that could occur during
+           the factorization of each chain.
+
+           If Control [UMFPACK_FRONT_ALLOC_INIT] is >= 0, the following
+           strategy is used.  If the AMD ordering was used, this non-negative
+           parameter is ignored.  A front of size (d+2)*(d+2) is allocated,
+           where d = Info [UMFPACK_SYMMETRIC_DMAX].  Otherwise, a front of
+           size Control [UMFPACK_FRONT_ALLOC_INIT] times the largest front
+           possible for this chain is allocated.
+
+           If Control [UMFPACK_FRONT_ALLOC_INIT] is negative, then a front of
+           size (-Control [UMFPACK_FRONT_ALLOC_INIT]) is allocated (where the
+           size is in terms of the number of numerical entries).  This is done
+           regardless of the ordering method or ordering strategy used.
+
+           Default: 0.5.
+
+       Control [UMFPACK_DROPTOL]:  This parameter is new to V4.2.
+
+           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).
+
+       ------------------------------------------------------------------------
+       The following statistics were added to Version 4.1:
+       ------------------------------------------------------------------------
+
+       Info [UMFPACK_NUMERIC_WALLTIME]:  The wallclock time taken, in seconds.
+
+       Info [UMFPACK_MAX_FRONT_NROWS]: the max number of
+           rows in any frontal matrix.
+
+       Info [UMFPACK_MAX_FRONT_NCOLS]: the max number of
+           columns in any frontal matrix.
+
+       Info [UMFPACK_WAS_SCALED]:  the scaling used, either UMFPACK_SCALE_NONE,
+           UMFPACK_SCALE_SUM, or UMFPACK_SCALE_MAX.
+
+       Info [UMFPACK_RSMIN]: if scaling is performed, the smallest scale factor
+           for any row (either the smallest sum of absolute entries, or the
+           smallest maximum of absolute entries).
+
+       Info [UMFPACK_RSMAX]: if scaling is performed, the largest scale factor
+           for any row (either the largest sum of absolute entries, or the
+           largest maximum of absolute entries).
+
+       Info [UMFPACK_ALLOC_INIT_USED]:  the initial allocation parameter used.
+
+       Info [UMFPACK_FORCED_UPDATES]:  the number of BLAS-3 updates to the
+           frontal matrices that were required because the frontal matrix
+           grew larger than its current working array.
+
+       Info [UMFPACK_NOFF_DIAG]: number of off-diagonal pivots selected, if the
+           symmetric or 2-by-2 strategies are used.
+
+       ------------------------------------------------------------------------
+       The following statistics were added to Version 4.2:
+       ------------------------------------------------------------------------
+
+       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/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_qsymbolic.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_qsymbolic.h
new file mode 100644 (file)
index 0000000..23088a1
--- /dev/null
@@ -0,0 +1,140 @@
+/* ========================================================================== */
+/* === umfpack_qsymbolic ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_qsymbolic
+(
+    int n_row,
+    int n_col,
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ],
+    const int Qinit [ ],
+    void **Symbolic,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+long umfpack_dl_qsymbolic
+(
+    long n_row,
+    long n_col,
+    const long Ap [ ],
+    const long Ai [ ],
+    const double Ax [ ],
+    const long Qinit [ ],
+    void **Symbolic,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+int umfpack_zi_qsymbolic
+(
+    int n_row,
+    int n_col,
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ], const double Az [ ],
+    const int Qinit [ ],
+    void **Symbolic,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+long umfpack_zl_qsymbolic
+(
+    long n_row,
+    long n_col,
+    const long Ap [ ],
+    const long Ai [ ],
+    const double Ax [ ], const double Az [ ],
+    const long Qinit [ ],
+    void **Symbolic,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    int n_row, n_col, *Ap, *Ai, *Qinit, status ;
+    double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax ;
+    status = umfpack_di_qsymbolic (n_row, n_col, Ap, Ai, Ax, Qinit,
+       &Symbolic, Control, Info) ;
+
+double long Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    long n_row, n_col, *Ap, *Ai, *Qinit, status ;
+    double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax ;
+    status = umfpack_dl_qsymbolic (n_row, n_col, Ap, Ai, Ax, Qinit,
+       &Symbolic, Control, Info) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    int n_row, n_col, *Ap, *Ai, *Qinit, status ;
+    double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax, *Az ;
+    status = umfpack_zi_qsymbolic (n_row, n_col, Ap, Ai, Ax, Az, Qinit,
+       &Symbolic, Control, Info) ;
+
+complex long Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    long n_row, n_col, *Ap, *Ai, *Qinit, status ;
+    double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax, *Az ;
+    status = umfpack_zl_qsymbolic (n_row, n_col, Ap, Ai, Ax, Az, Qinit,
+       &Symbolic, Control, Info) ;
+
+Purpose:
+
+    Given the nonzero pattern of a sparse matrix A in column-oriented form, and
+    a sparsity preserving column pre-ordering Qinit, umfpack_*_qsymbolic
+    performs the symbolic factorization of A*Qinit (or A (:,Qinit) in MATLAB
+    notation).  This is identical to umfpack_*_symbolic, except that neither
+    COLAMD nor AMD are called and the user input column order Qinit is used
+    instead.  Note that in general, the Qinit passed to umfpack_*_qsymbolic
+    can differ from the final Q found in umfpack_*_numeric.  The unsymmetric
+    strategy will perform a column etree postordering done in
+    umfpack_*_qsymbolic and sparsity-preserving modifications are made within
+    each frontal matrix during umfpack_*_numeric.  The symmetric and 2-by-2
+    strategies will preserve Qinit, unless the matrix is structurally singular.
+
+    See umfpack_*_symbolic for more information.
+
+    *** WARNING ***  A poor choice of Qinit can easily cause umfpack_*_numeric
+    to use a huge amount of memory and do a lot of work.  The "default" symbolic
+    analysis method is umfpack_*_symbolic, not this routine.  If you use this
+    routine, the performance of UMFPACK is your responsibility;  UMFPACK will
+    not try to second-guess a poor choice of Qinit.
+
+Returns:
+
+    The value of Info [UMFPACK_STATUS]; see umfpack_*_symbolic.
+    Also returns UMFPACK_ERROR_invalid_permuation if Qinit is not a valid
+    permutation vector.
+
+Arguments:
+
+    All arguments are the same as umfpack_*_symbolic, except for the following:
+
+    Int Qinit [n_col] ;                Input argument, not modified.
+
+       The user's fill-reducing initial column pre-ordering.  This must be a
+       permutation of 0..n_col-1.  If Qinit [k] = j, then column j is the kth
+       column of the matrix A (:,Qinit) to be factorized.  If Qinit is an
+       (Int *) NULL pointer, then COLAMD or AMD are called instead.
+
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_control.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_control.h
new file mode 100644 (file)
index 0000000..6aebfdf
--- /dev/null
@@ -0,0 +1,77 @@
+/* ========================================================================== */
+/* === umfpack_report_control =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+void umfpack_di_report_control
+(
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+void umfpack_dl_report_control
+(
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+void umfpack_zi_report_control
+(
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+void umfpack_zl_report_control
+(
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL] ;
+    umfpack_di_report_control (Control) ;
+
+double long Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL] ;
+    umfpack_dl_report_control (Control) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL] ;
+    umfpack_zi_report_control (Control) ;
+
+double long Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL] ;
+    umfpack_zl_report_control (Control) ;
+
+Purpose:
+
+    Prints the current control settings.  Note that with the default print
+    level, nothing is printed.  Does nothing if Control is (double *) NULL.
+
+Arguments:
+
+    double Control [UMFPACK_CONTROL] ;   Input argument, not modified.
+
+       If a (double *) NULL pointer is passed, then the default control
+       settings are used.  Otherwise, the settings are determined from the
+       Control array.  See umfpack_*_defaults on how to fill the Control
+       array with the default settings.  If Control contains NaN's, the
+       defaults are used.  The following Control parameters are used:
+
+       Control [UMFPACK_PRL]:  printing level.
+
+           1 or less: no output
+           2 or more: print all of Control
+           Default: 1
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_info.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_info.h
new file mode 100644 (file)
index 0000000..ccba175
--- /dev/null
@@ -0,0 +1,87 @@
+/* ========================================================================== */
+/* === umfpack_report_info ================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+void umfpack_di_report_info
+(
+    const double Control [UMFPACK_CONTROL],
+    const double Info [UMFPACK_INFO]
+) ;
+
+void umfpack_dl_report_info
+(
+    const double Control [UMFPACK_CONTROL],
+    const double Info [UMFPACK_INFO]
+) ;
+
+void umfpack_zi_report_info
+(
+    const double Control [UMFPACK_CONTROL],
+    const double Info [UMFPACK_INFO]
+) ;
+
+void umfpack_zl_report_info
+(
+    const double Control [UMFPACK_CONTROL],
+    const double Info [UMFPACK_INFO]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ;
+    umfpack_di_report_info (Control, Info) ;
+
+double long Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ;
+    umfpack_dl_report_info (Control, Info) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ;
+    umfpack_zi_report_info (Control, Info) ;
+
+complex long Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ;
+    umfpack_zl_report_info (Control, Info) ;
+
+Purpose:
+
+    Reports statistics from the umfpack_*_*symbolic, umfpack_*_numeric, and
+    umfpack_*_*solve routines.
+
+Arguments:
+
+    double Control [UMFPACK_CONTROL] ;   Input argument, not modified.
+
+       If a (double *) NULL pointer is passed, then the default control
+       settings are used.  Otherwise, the settings are determined from the
+       Control array.  See umfpack_*_defaults on how to fill the Control
+       array with the default settings.  If Control contains NaN's, the
+       defaults are used.  The following Control parameters are used:
+
+       Control [UMFPACK_PRL]:  printing level.
+
+           0 or less: no output, even when an error occurs
+           1: error messages only
+           2 or more: error messages, and print all of Info
+           Default: 1
+
+    double Info [UMFPACK_INFO] ;               Input argument, not modified.
+
+       Info is an output argument of several UMFPACK routines.
+       The contents of Info are printed on standard output.
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_matrix.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_matrix.h
new file mode 100644 (file)
index 0000000..b0225da
--- /dev/null
@@ -0,0 +1,198 @@
+/* ========================================================================== */
+/* === umfpack_report_matrix ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_report_matrix
+(
+    int n_row,
+    int n_col,
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ],
+    int col_form,
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+long umfpack_dl_report_matrix
+(
+    long n_row,
+    long n_col,
+    const long Ap [ ],
+    const long Ai [ ],
+    const double Ax [ ],
+    long col_form,
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+int umfpack_zi_report_matrix
+(
+    int n_row,
+    int n_col,
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ], const double Az [ ],
+    int col_form,
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+long umfpack_zl_report_matrix
+(
+    long n_row,
+    long n_col,
+    const long Ap [ ],
+    const long Ai [ ],
+    const double Ax [ ], const double Az [ ],
+    long col_form,
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    int n_row, n_col, *Ap, *Ai, status ;
+    double *Ax, Control [UMFPACK_CONTROL] ;
+    status = umfpack_di_report_matrix (n_row, n_col, Ap, Ai, Ax, 1, Control) ;
+or:
+    status = umfpack_di_report_matrix (n_row, n_col, Ap, Ai, Ax, 0, Control) ;
+
+double long Syntax:
+
+    #include "umfpack.h"
+    long n_row, n_col, *Ap, *Ai, status ;
+    double *Ax, Control [UMFPACK_CONTROL] ;
+    status = umfpack_dl_report_matrix (n_row, n_col, Ap, Ai, Ax, 1, Control) ;
+or:
+    status = umfpack_dl_report_matrix (n_row, n_col, Ap, Ai, Ax, 0, Control) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    int n_row, n_col, *Ap, *Ai, status ;
+    double *Ax, *Az, Control [UMFPACK_CONTROL] ;
+    status = umfpack_zi_report_matrix (n_row, n_col, Ap, Ai, Ax, Az, 1,
+        Control) ;
+or:
+    status = umfpack_zi_report_matrix (n_row, n_col, Ap, Ai, Ax, Az, 0,
+        Control) ;
+
+complex long Syntax:
+
+    #include "umfpack.h"
+    long n_row, n_col, *Ap, *Ai, status ;
+    double *Ax, Control [UMFPACK_CONTROL] ;
+    status = umfpack_zl_report_matrix (n_row, n_col, Ap, Ai, Ax, Az, 1,
+       Control) ;
+or:
+    status = umfpack_zl_report_matrix (n_row, n_col, Ap, Ai, Ax, Az, 0,
+       Control) ;
+
+Purpose:
+
+    Verifies and prints a row or column-oriented sparse matrix.
+
+Returns:
+
+    UMFPACK_OK if Control [UMFPACK_PRL] <= 2 (the input is not checked).
+
+    Otherwise (where n is n_col for the column form and n_row for row
+    and let ni be n_row for the column form and n_col for row):
+
+    UMFPACK_OK if the matrix is valid.
+
+    UMFPACK_ERROR_n_nonpositive if n_row <= 0 or n_col <= 0.
+    UMFPACK_ERROR_argument_missing if Ap and/or Ai are missing.
+    UMFPACK_ERROR_invalid_matrix if Ap [n] < 0, if Ap [0] is not zero,
+       if Ap [j+1] < Ap [j] for any j in the range 0 to n-1,
+       if any row index in Ai is not in the range 0 to ni-1, or
+       if the row indices in any column are not in
+       ascending order, or contain duplicates.
+    UMFPACK_ERROR_out_of_memory if out of memory.
+
+Arguments:
+
+    Int n_row ;                Input argument, not modified.
+    Int n_col ;                Input argument, not modified.
+
+       A is an n_row-by-n_row matrix.  Restriction: n_row > 0 and n_col > 0.
+
+    Int Ap [n+1] ;     Input argument, not modified.
+
+       n is n_row for a row-form matrix, and n_col for a column-form matrix.
+
+       Ap is an integer array of size n+1.  If col_form is true (nonzero),
+       then on input, it holds the "pointers" for the column form of the
+       sparse matrix A.  The row indices of column j of the matrix A are held
+       in Ai [(Ap [j]) ... (Ap [j+1]-1)].  Otherwise, Ap holds the
+       row pointers, and the column indices of row j of the matrix are held
+       in Ai [(Ap [j]) ... (Ap [j+1]-1)].
+
+       The first entry, Ap [0], must be zero, and Ap [j] <= Ap [j+1] must hold
+       for all j in the range 0 to n-1.  The value nz = Ap [n] is thus the
+       total number of entries in the pattern of the matrix A.
+
+    Int Ai [nz] ;      Input argument, not modified, of size nz = Ap [n].
+
+       If col_form is true (nonzero), then the nonzero pattern (row indices)
+       for column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)].  Row indices
+       must be in the range 0 to n_row-1 (the matrix is 0-based).
+
+       Otherwise, the nonzero pattern (column indices) for row j is stored in
+       Ai [(Ap [j]) ... (Ap [j+1]-1)]. Column indices must be in the range 0
+       to n_col-1 (the matrix is 0-based).
+
+    double Ax [nz] ;   Input argument, not modified, of size nz = Ap [n].
+
+       The numerical values of the sparse matrix A.
+
+       If col_form is true (nonzero), then the nonzero pattern (row indices)
+       for column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)], and the
+       corresponding (real) numerical values are stored in
+       Ax [(Ap [j]) ... (Ap [j+1]-1)].  The imaginary parts are stored in
+       Az [(Ap [j]) ... (Ap [j+1]-1)], for the complex versions.
+
+       Otherwise, the nonzero pattern (column indices) for row j
+       is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)], and the corresponding
+       (real) numerical values are stored in Ax [(Ap [j]) ... (Ap [j+1]-1)].
+       The imaginary parts are stored in Az [(Ap [j]) ... (Ap [j+1]-1)],
+       for the complex versions.
+
+       No numerical values are printed if Ax or Az are (double *) NULL.
+
+    double Az [nz] ;   Input argument, not modified, for complex versions.
+
+       The imaginary values of the sparse matrix A.   See the description
+       of Ax, above.  No numerical values are printed if Az is NULL. 
+
+       Future complex version:  if Ax is present and Az is NULL, then both real
+       and imaginary parts will be contained in Ax[0..2*nz-1], with Ax[2*k]
+       and Ax[2*k+1] being the real and imaginary part of the kth entry.
+
+    Int col_form ;     Input argument, not modified.
+
+       The matrix is in row-oriented form if form is col_form is false (0).
+       Otherwise, the matrix is in column-oriented form.
+
+    double Control [UMFPACK_CONTROL] ; Input argument, not modified.
+
+       If a (double *) NULL pointer is passed, then the default control
+       settings are used.  Otherwise, the settings are determined from the
+       Control array.  See umfpack_*_defaults on how to fill the Control
+       array with the default settings.  If Control contains NaN's, the
+       defaults are used.  The following Control parameters are used:
+
+       Control [UMFPACK_PRL]:  printing level.
+
+           2 or less: no output.  returns silently without checking anything.
+           3: fully check input, and print a short summary of its status
+           4: as 3, but print first few entries of the input
+           5: as 3, but print all of the input
+           Default: 1
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_numeric.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_numeric.h
new file mode 100644 (file)
index 0000000..54fd8f7
--- /dev/null
@@ -0,0 +1,113 @@
+/* ========================================================================== */
+/* === umfpack_report_numeric =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_report_numeric
+(
+    void *Numeric,
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+long umfpack_dl_report_numeric
+(
+    void *Numeric,
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+int umfpack_zi_report_numeric
+(
+    void *Numeric,
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+long umfpack_zl_report_numeric
+(
+    void *Numeric,
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    double Control [UMFPACK_CONTROL] ;
+    int status ;
+    status = umfpack_di_report_numeric (Numeric, Control) ;
+
+double long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    double Control [UMFPACK_CONTROL] ;
+    long status ;
+    status = umfpack_dl_report_numeric (Numeric, Control) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    double Control [UMFPACK_CONTROL] ;
+    int status ;
+    status = umfpack_zi_report_numeric (Numeric, Control) ;
+
+complex long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    double Control [UMFPACK_CONTROL] ;
+    long status ;
+    status = umfpack_zl_report_numeric (Numeric, Control) ;
+
+Purpose:
+
+    Verifies and prints a Numeric object (the LU factorization, both its pattern
+    numerical values, and permutation vectors P and Q).  This routine checks the
+    object more carefully than the computational routines.  Normally, this check
+    is not required, since umfpack_*_numeric either returns (void *) NULL, or a
+    valid Numeric object.  However, if you suspect that your own code has
+    corrupted the Numeric object (by overruning memory bounds, for example),
+    then this routine might be able to detect a corrupted Numeric object.  Since
+    this is a complex object, not all such user-generated errors are guaranteed
+    to be caught by this routine.
+
+Returns:
+
+    UMFPACK_OK if Control [UMFPACK_PRL] <= 2 (the input is not checked).
+
+    Otherwise:
+
+    UMFPACK_OK if the Numeric object is valid.
+    UMFPACK_ERROR_invalid_Numeric_object if the Numeric object is invalid.
+    UMFPACK_ERROR_out_of_memory if out of memory.
+
+Arguments:
+
+    void *Numeric ;                    Input argument, not modified.
+
+       The Numeric object, which holds the numeric factorization computed by
+       umfpack_*_numeric.
+
+    double Control [UMFPACK_CONTROL] ; Input argument, not modified.
+
+       If a (double *) NULL pointer is passed, then the default control
+       settings are used.  Otherwise, the settings are determined from the
+       Control array.  See umfpack_*_defaults on how to fill the Control
+       array with the default settings.  If Control contains NaN's, the
+       defaults are used.  The following Control parameters are used:
+
+       Control [UMFPACK_PRL]:  printing level.
+
+           2 or less: no output.  returns silently without checking anything.
+           3: fully check input, and print a short summary of its status
+           4: as 3, but print first few entries of the input
+           5: as 3, but print all of the input
+           Default: 1
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_perm.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_perm.h
new file mode 100644 (file)
index 0000000..17969dd
--- /dev/null
@@ -0,0 +1,113 @@
+/* ========================================================================== */
+/* === umfpack_report_perm ================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_report_perm
+(
+    int np,
+    const int Perm [ ],
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+long umfpack_dl_report_perm
+(
+    long np,
+    const long Perm [ ],
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+int umfpack_zi_report_perm
+(
+    int np,
+    const int Perm [ ],
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+long umfpack_zl_report_perm
+(
+    long np,
+    const long Perm [ ],
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    int np, *Perm, status ;
+    double Control [UMFPACK_CONTROL] ;
+    status = umfpack_di_report_perm (np, Perm, Control) ;
+
+double long Syntax:
+
+    #include "umfpack.h"
+    long np, *Perm, status ;
+    double Control [UMFPACK_CONTROL] ;
+    status = umfpack_dl_report_perm (np, Perm, Control) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    int np, *Perm, status ;
+    double Control [UMFPACK_CONTROL] ;
+    status = umfpack_zi_report_perm (np, Perm, Control) ;
+
+complex long Syntax:
+
+    #include "umfpack.h"
+    long np, *Perm, status ;
+    double Control [UMFPACK_CONTROL] ;
+    status = umfpack_zl_report_perm (np, Perm, Control) ;
+
+Purpose:
+
+    Verifies and prints a permutation vector.
+
+Returns:
+
+    UMFPACK_OK if Control [UMFPACK_PRL] <= 2 (the input is not checked).
+
+    Otherwise:
+    UMFPACK_OK if the permutation vector is valid (this includes that case
+       when Perm is (Int *) NULL, which is not an error condition).
+    UMFPACK_ERROR_n_nonpositive if np <= 0.
+    UMFPACK_ERROR_out_of_memory if out of memory.
+    UMFPACK_ERROR_invalid_permutation if Perm is not a valid permutation vector.
+
+Arguments:
+
+    Int np ;           Input argument, not modified.
+
+       Perm is an integer vector of size np.  Restriction: np > 0.
+
+    Int Perm [np] ;    Input argument, not modified.
+
+       A permutation vector of size np.  If Perm is not present (an (Int *)
+       NULL pointer), then it is assumed to be the identity permutation.  This
+       is consistent with its use as an input argument to umfpack_*_qsymbolic,
+       and is not an error condition.  If Perm is present, the entries in Perm
+       must range between 0 and np-1, and no duplicates may exist.
+
+    double Control [UMFPACK_CONTROL] ; Input argument, not modified.
+
+       If a (double *) NULL pointer is passed, then the default control
+       settings are used.  Otherwise, the settings are determined from the
+       Control array.  See umfpack_*_defaults on how to fill the Control
+       array with the default settings.  If Control contains NaN's, the
+       defaults are used.  The following Control parameters are used:
+
+       Control [UMFPACK_PRL]:  printing level.
+
+           2 or less: no output.  returns silently without checking anything.
+           3: fully check input, and print a short summary of its status
+           4: as 3, but print first few entries of the input
+           5: as 3, but print all of the input
+           Default: 1
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_status.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_status.h
new file mode 100644 (file)
index 0000000..7d826de
--- /dev/null
@@ -0,0 +1,91 @@
+/* ========================================================================== */
+/* === umfpack_report_status ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+void umfpack_di_report_status
+(
+    const double Control [UMFPACK_CONTROL],
+    int status
+) ;
+
+void umfpack_dl_report_status
+(
+    const double Control [UMFPACK_CONTROL],
+    long status
+) ;
+
+void umfpack_zi_report_status
+(
+    const double Control [UMFPACK_CONTROL],
+    int status
+) ;
+
+void umfpack_zl_report_status
+(
+    const double Control [UMFPACK_CONTROL],
+    long status
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL] ;
+    int status ;
+    umfpack_di_report_status (Control, status) ;
+
+double long Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL] ;
+    long status ;
+    umfpack_dl_report_status (Control, status) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL] ;
+    int status ;
+    umfpack_zi_report_status (Control, status) ;
+
+complex long Syntax:
+
+    #include "umfpack.h"
+    double Control [UMFPACK_CONTROL] ;
+    long status ;
+    umfpack_zl_report_status (Control, status) ;
+
+Purpose:
+
+    Prints the status (return value) of other umfpack_* routines.
+
+Arguments:
+
+    double Control [UMFPACK_CONTROL] ;   Input argument, not modified.
+
+       If a (double *) NULL pointer is passed, then the default control
+       settings are used.  Otherwise, the settings are determined from the
+       Control array.  See umfpack_*_defaults on how to fill the Control
+       array with the default settings.  If Control contains NaN's, the
+       defaults are used.  The following Control parameters are used:
+
+       Control [UMFPACK_PRL]:  printing level.
+
+           0 or less: no output, even when an error occurs
+           1: error messages only
+           2 or more: print status, whether or not an error occured
+           4 or more: also print the UMFPACK Copyright
+           6 or more: also print the UMFPACK License
+           Default: 1
+
+    Int status ;                       Input argument, not modified.
+
+       The return value from another umfpack_* routine.
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_symbolic.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_symbolic.h
new file mode 100644 (file)
index 0000000..f9d9f12
--- /dev/null
@@ -0,0 +1,112 @@
+/* ========================================================================== */
+/* === umfpack_report_symbolic ============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_report_symbolic
+(
+    void *Symbolic,
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+long umfpack_dl_report_symbolic
+(
+    void *Symbolic,
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+int umfpack_zi_report_symbolic
+(
+    void *Symbolic,
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+long umfpack_zl_report_symbolic
+(
+    void *Symbolic,
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    double Control [UMFPACK_CONTROL] ;
+    int status ;
+    status = umfpack_di_report_symbolic (Symbolic, Control) ;
+
+double long Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    double Control [UMFPACK_CONTROL] ;
+    long status ;
+    status = umfpack_dl_report_symbolic (Symbolic, Control) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    double Control [UMFPACK_CONTROL] ;
+    int status ;
+    status = umfpack_zi_report_symbolic (Symbolic, Control) ;
+
+complex long Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    double Control [UMFPACK_CONTROL] ;
+    long status ;
+    status = umfpack_zl_report_symbolic (Symbolic, Control) ;
+
+Purpose:
+
+    Verifies and prints a Symbolic object.  This routine checks the object more
+    carefully than the computational routines.  Normally, this check is not
+    required, since umfpack_*_*symbolic either returns (void *) NULL, or a valid
+    Symbolic object.  However, if you suspect that your own code has corrupted
+    the Symbolic object (by overruning memory bounds, for example), then this
+    routine might be able to detect a corrupted Symbolic object.  Since this is
+    a complex object, not all such user-generated errors are guaranteed to be
+    caught by this routine.
+
+Returns:
+
+    UMFPACK_OK if Control [UMFPACK_PRL] is <= 2 (no inputs are checked).
+
+    Otherwise:
+
+    UMFPACK_OK if the Symbolic object is valid.
+    UMFPACK_ERROR_invalid_Symbolic_object if the Symbolic object is invalid.
+    UMFPACK_ERROR_out_of_memory if out of memory.
+
+Arguments:
+
+    void *Symbolic ;                   Input argument, not modified.
+
+       The Symbolic object, which holds the symbolic factorization computed by
+       umfpack_*_*symbolic.
+
+    double Control [UMFPACK_CONTROL] ; Input argument, not modified.
+
+       If a (double *) NULL pointer is passed, then the default control
+       settings are used.  Otherwise, the settings are determined from the
+       Control array.  See umfpack_*_defaults on how to fill the Control
+       array with the default settings.  If Control contains NaN's, the
+       defaults are used.  The following Control parameters are used:
+
+       Control [UMFPACK_PRL]:  printing level.
+
+           2 or less: no output.  returns silently without checking anything.
+           3: fully check input, and print a short summary of its status
+           4: as 3, but print first few entries of the input
+           5: as 3, but print all of the input
+           Default: 1
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_triplet.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_triplet.h
new file mode 100644 (file)
index 0000000..9286754
--- /dev/null
@@ -0,0 +1,149 @@
+/* ========================================================================== */
+/* === umfpack_report_triplet =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_report_triplet
+(
+    int n_row,
+    int n_col,
+    int nz,
+    const int Ti [ ],
+    const int Tj [ ],
+    const double Tx [ ],
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+long umfpack_dl_report_triplet
+(
+    long n_row,
+    long n_col,
+    long nz,
+    const long Ti [ ],
+    const long Tj [ ],
+    const double Tx [ ],
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+int umfpack_zi_report_triplet
+(
+    int n_row,
+    int n_col,
+    int nz,
+    const int Ti [ ],
+    const int Tj [ ],
+    const double Tx [ ], const double Tz [ ],
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+long umfpack_zl_report_triplet
+(
+    long n_row,
+    long n_col,
+    long nz,
+    const long Ti [ ],
+    const long Tj [ ],
+    const double Tx [ ], const double Tz [ ],
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    int n_row, n_col, nz, *Ti, *Tj, status ;
+    double *Tx, Control [UMFPACK_CONTROL] ;
+    status = umfpack_di_report_triplet (n_row, n_col, nz, Ti, Tj, Tx, Control) ;
+
+double long Syntax:
+
+    #include "umfpack.h"
+    long n_row, n_col, nz, *Ti, *Tj, status ;
+    double *Tx, Control [UMFPACK_CONTROL] ;
+    status = umfpack_dl_report_triplet (n_row, n_col, nz, Ti, Tj, Tx, Control) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    int n_row, n_col, nz, *Ti, *Tj, status ;
+    double *Tx, *Tz, Control [UMFPACK_CONTROL] ;
+    status = umfpack_zi_report_triplet (n_row, n_col, nz, Ti, Tj, Tx, Tz,
+       Control) ;
+
+complex long Syntax:
+
+    #include "umfpack.h"
+    long n_row, n_col, nz, *Ti, *Tj, status ;
+    double *Tx, *Tz, Control [UMFPACK_CONTROL] ;
+    status = umfpack_zl_report_triplet (n_row, n_col, nz, Ti, Tj, Tx, Tz,
+       Control) ;
+
+Purpose:
+
+    Verifies and prints a matrix in triplet form.
+
+Returns:
+
+    UMFPACK_OK if Control [UMFPACK_PRL] <= 2 (the input is not checked).
+
+    Otherwise:
+
+    UMFPACK_OK if the Triplet matrix is OK.
+    UMFPACK_ERROR_argument_missing if Ti and/or Tj are missing.
+    UMFPACK_ERROR_n_nonpositive if n_row <= 0 or n_col <= 0.
+    UMFPACK_ERROR_invalid_matrix if nz < 0, or
+       if any row or column index in Ti and/or Tj
+       is not in the range 0 to n_row-1 or 0 to n_col-1, respectively.
+
+Arguments:
+
+    Int n_row ;                Input argument, not modified.
+    Int n_col ;                Input argument, not modified.
+
+       A is an n_row-by-n_col matrix.
+
+    Int nz ;           Input argument, not modified.
+
+       The number of entries in the triplet form of the matrix.
+
+    Int Ti [nz] ;      Input argument, not modified.
+    Int Tj [nz] ;      Input argument, not modified.
+    double Tx [nz] ;   Input argument, not modified.
+    double Tz [nz] ;   Input argument, not modified, for complex versions.
+
+       Ti, Tj, Tx (and Tz for complex versions) hold the "triplet" form of a
+       sparse matrix.  The kth nonzero entry is in row i = Ti [k], column
+       j = Tj [k], the real numerical value of a_ij is Tx [k], and the
+       imaginary part of a_ij is Tz [k] (for complex versions).  The row and
+       column indices i and j must be in the range 0 to n_row-1 or 0 to
+       n_col-1, respectively.  Duplicate entries may be present.  The
+       "triplets" may be in any order.  Tx and Tz are optional; if Tx or Tz are
+       not present ((double *) NULL pointers), then the numerical values are
+       not printed.
+
+       Future complex version:  if Tx is present and Tz is NULL, then both real
+       and imaginary parts will be contained in Tx[0..2*nz-1], with Tx[2*k]
+       and Tx[2*k+1] being the real and imaginary part of the kth entry.
+
+    double Control [UMFPACK_CONTROL] ; Input argument, not modified.
+
+       If a (double *) NULL pointer is passed, then the default control
+       settings are used.  Otherwise, the settings are determined from the
+       Control array.  See umfpack_*_defaults on how to fill the Control
+       array with the default settings.  If Control contains NaN's, the
+       defaults are used.  The following Control parameters are used:
+
+       Control [UMFPACK_PRL]:  printing level.
+
+           2 or less: no output.  returns silently without checking anything.
+           3: fully check input, and print a short summary of its status
+           4: as 3, but print first few entries of the input
+           5: as 3, but print all of the input
+           Default: 1
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_vector.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_vector.h
new file mode 100644 (file)
index 0000000..66db99d
--- /dev/null
@@ -0,0 +1,134 @@
+/* ========================================================================== */
+/* === umfpack_report_vector ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_report_vector
+(
+    int n,
+    const double X [ ],
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+long umfpack_dl_report_vector
+(
+    long n,
+    const double X [ ],
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+int umfpack_zi_report_vector
+(
+    int n,
+    const double Xx [ ], const double Xz [ ],
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+long umfpack_zl_report_vector
+(
+    long n,
+    const double Xx [ ], const double Xz [ ],
+    const double Control [UMFPACK_CONTROL]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    int n, status ;
+    double *X, Control [UMFPACK_CONTROL] ;
+    status = umfpack_di_report_vector (n, X, Control) ;
+
+double long Syntax:
+
+    #include "umfpack.h"
+    long n, status ;
+    double *X, Control [UMFPACK_CONTROL] ;
+    status = umfpack_dl_report_vector (n, X, Control) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    int n, status ;
+    double *Xx, *Xz, Control [UMFPACK_CONTROL] ;
+    status = umfpack_zi_report_vector (n, Xx, Xz, Control) ;
+
+complex long Syntax:
+
+    #include "umfpack.h"
+    long n, status ;
+    double *Xx, *Xz, Control [UMFPACK_CONTROL] ;
+    status = umfpack_zl_report_vector (n, Xx, Xz, Control) ;
+
+Purpose:
+
+    Verifies and prints a dense vector.
+
+Returns:
+
+    UMFPACK_OK if Control [UMFPACK_PRL] <= 2 (the input is not checked).
+
+    Otherwise:
+    
+    UMFPACK_OK if the vector is valid.
+    UMFPACK_ERROR_argument_missing if X or Xx is missing.
+    UMFPACK_ERROR_n_nonpositive if n <= 0.
+
+Arguments:
+
+    Int n ;            Input argument, not modified.
+
+       X is a real or complex vector of size n.  Restriction: n > 0.
+
+    double X [n] ;     Input argument, not modified.  For real versions.
+
+       A real vector of size n.  X must not be (double *) NULL.
+
+    double Xx [n or 2*n] ; Input argument, not modified.  For complex versions.
+    double Xz [n or 0] ;   Input argument, not modified.  For complex versions.
+
+       A complex vector of size n, in one of two storage formats.
+       Xx must not be (double *) NULL.
+
+       If Xz is not (double *) NULL, then Xx [i] is the real part of X (i) and
+       Xz [i] is the imaginary part of X (i).  Both vectors are of length n.
+       This is the "split" form of the complex vector X.
+
+       If Xz is (double *) NULL, then Xx holds both real and imaginary parts,
+       where Xx [2*i] is the real part of X (i) and Xx [2*i+1] is the imaginary
+       part of X (i).  Xx is of length 2*n doubles.  If you have an ANSI C99
+       compiler with the intrinsic double _Complex type, then Xx can be of
+       type double _Complex in the calling routine and typecast to (double *)
+       when passed to umfpack_*_report_vector (this is untested, however).
+       This is the "merged" form of the complex vector X.
+
+       Future work:  all complex routines in UMFPACK could use this same
+       strategy for their complex arguments.  The split format is useful for
+       MATLAB, which holds its real and imaginary parts in seperate arrays.
+       The merged format is compatible with the intrinsic double _Complex
+       type in ANSI C99, and is also compatible with SuperLU's method of
+       storing complex matrices.  In the current version, only 
+       umfpack_*_report_vector supports both formats.
+
+    double Control [UMFPACK_CONTROL] ; Input argument, not modified.
+
+       If a (double *) NULL pointer is passed, then the default control
+       settings are used.  Otherwise, the settings are determined from the
+       Control array.  See umfpack_*_defaults on how to fill the Control
+       array with the default settings.  If Control contains NaN's, the
+       defaults are used.  The following Control parameters are used:
+
+       Control [UMFPACK_PRL]:  printing level.
+
+           2 or less: no output.  returns silently without checking anything.
+           3: fully check input, and print a short summary of its status
+           4: as 3, but print first few entries of the input
+           5: as 3, but print all of the input
+           Default: 1
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_save_numeric.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_save_numeric.h
new file mode 100644 (file)
index 0000000..0e3f57b
--- /dev/null
@@ -0,0 +1,93 @@
+/* ========================================================================== */
+/* === umfpack_save_numeric ================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_save_numeric
+(
+    void *Numeric,
+    char *filename
+) ;
+
+long umfpack_dl_save_numeric
+(
+    void *Numeric,
+    char *filename
+) ;
+
+int umfpack_zi_save_numeric
+(
+    void *Numeric,
+    char *filename
+) ;
+
+long umfpack_zl_save_numeric
+(
+    void *Numeric,
+    char *filename
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    int status ;
+    char *filename ;
+    void *Numeric ;
+    status = umfpack_di_save_numeric (Numeric, filename) ;
+
+double long Syntax:
+
+    #include "umfpack.h"
+    long status ;
+    char *filename ;
+    void *Numeric ;
+    status = umfpack_dl_save_numeric (Numeric, filename) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    int status ;
+    char *filename ;
+    void *Numeric ;
+    status = umfpack_zi_save_numeric (Numeric, filename) ;
+
+complex long Syntax:
+
+    #include "umfpack.h"
+    long status ;
+    char *filename ;
+    void *Numeric ;
+    status = umfpack_zl_save_numeric (Numeric, filename) ;
+
+Purpose:
+
+    Saves a Numeric object to a file, which can later be read by
+    umfpack_*_load_numeric.  The Numeric object is not modified.  You need
+    to call umfpack_*_free_numeric if you to delete the Numeric object after
+    saving it to a file.
+
+Returns:
+
+    UMFPACK_OK if successful.
+    UMFPACK_ERROR_invalid_Numeric_object if Numeric is not valid.
+    UMFPACK_ERROR_file_IO if an I/O error occurred.
+
+Arguments:
+
+    void *Numeric ;        Input argument, not modified.
+
+       Numeric must point to a valid Numeric object, computed by
+       umfpack_*_numeric or loaded by umfpack_*_load_numeric.
+
+    char *filename ;       Input argument, not modified.
+
+       A string that contains the filename to which the Numeric
+       object is written.
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_save_symbolic.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_save_symbolic.h
new file mode 100644 (file)
index 0000000..a183ede
--- /dev/null
@@ -0,0 +1,93 @@
+/* ========================================================================== */
+/* === umfpack_save_symbolic================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_save_symbolic
+(
+    void *Symbolic,
+    char *filename
+) ;
+
+long umfpack_dl_save_symbolic
+(
+    void *Symbolic,
+    char *filename
+) ;
+
+int umfpack_zi_save_symbolic
+(
+    void *Symbolic,
+    char *filename
+) ;
+
+long umfpack_zl_save_symbolic
+(
+    void *Symbolic,
+    char *filename
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    int status ;
+    char *filename ;
+    void *Symbolic ;
+    status = umfpack_di_save_symbolic (Symbolic, filename) ;
+
+double long Syntax:
+
+    #include "umfpack.h"
+    long status ;
+    char *filename ;
+    void *Symbolic ;
+    status = umfpack_dl_save_symbolic (Symbolic, filename) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    int status ;
+    char *filename ;
+    void *Symbolic ;
+    status = umfpack_zi_save_symbolic (Symbolic, filename) ;
+
+complex long Syntax:
+
+    #include "umfpack.h"
+    long status ;
+    char *filename ;
+    void *Symbolic ;
+    status = umfpack_zl_save_symbolic (Symbolic, filename) ;
+
+Purpose:
+
+    Saves a Symbolic object to a file, which can later be read by
+    umfpack_*_load_symbolic.  The Symbolic object is not modified.  You need
+    to call umfpack_*_free_symbolic if you to delete the Symbolic object after
+    saving it to a file.
+
+Returns:
+
+    UMFPACK_OK if successful.
+    UMFPACK_ERROR_invalid_Symbolic_object if Symbolic is not valid.
+    UMFPACK_ERROR_file_IO if an I/O error occurred.
+
+Arguments:
+
+    void *Symbolic ;       Input argument, not modified.
+
+       Symbolic must point to a valid Symbolic object, computed by
+       umfpack_*_symbolic or loaded by umfpack_*_load_symbolic.
+
+    char *filename ;       Input argument, not modified.
+
+       A string that contains the filename to which the Symbolic
+       object is written.
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_scale.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_scale.h
new file mode 100644 (file)
index 0000000..8e254f8
--- /dev/null
@@ -0,0 +1,105 @@
+/* ========================================================================== */
+/* === umfpack_scale ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_scale
+(
+    double X [ ],
+    const double B [ ],
+    void *Numeric
+) ;
+
+long umfpack_dl_scale
+(
+    double X [ ],
+    const double B [ ],
+    void *Numeric
+) ;
+
+int umfpack_zi_scale
+(
+    double Xx [ ],      double Xz [ ],
+    const double Bx [ ], const double Bz [ ],
+    void *Numeric
+) ;
+
+long umfpack_zl_scale
+(
+    double Xx [ ],      double Xz [ ],
+    const double Bx [ ], const double Bz [ ],
+    void *Numeric
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    double *B, *X ;
+    status = umfpack_di_scale (X, B, Numeric) ;
+
+double long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    double *B, *X ;
+    status = umfpack_dl_scale (X, B, Numeric) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    double *Bx, *Bz, *Xx, *Xz ;
+    status = umfpack_zi_scale (Xx, Xz, Bx, Bz, Numeric) ;
+
+complex long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    double *Bx, *Bz, *Xx, *Xz ;
+    status = umfpack_zl_scale (Xx, Xz, Bx, Bz, Numeric) ;
+
+Purpose:
+
+    Given LU factors computed by umfpack_*_numeric (PAQ=LU, PRAQ=LU, or
+    P(R\A)Q=LU), and a vector B, this routine computes X = B, X = R*B, or
+    X = R\B, as appropriate.  X and B must be vectors equal in length to the
+    number of rows of A.
+
+Returns:
+
+    The status code is returned.  UMFPACK_OK is returned if successful.
+    UMFPACK_ERROR_invalid_Numeric_object is returned in the Numeric
+    object is invalid.  UMFPACK_ERROR_argument_missing is returned if
+    any of the input vectors are missing (X and B for the real version,
+    and Xx, Xz, Bx, and Bz for the complex version).
+
+Arguments:
+
+    double X [n_row] ; Output argument.
+    or:
+    double Xx [n_row] ;        Output argument, real part.
+    double Xz [n_row] ;        Output argument, imaginary part.
+
+       The output vector X.
+
+    double B [n_row] ; Input argument, not modified.
+    or:
+    double Bx [n_row] ;        Input argument, not modified, real part.
+    double Bz [n_row] ;        Input argument, not modified, imaginary part.
+
+       The input vector B.
+
+    void *Numeric ;            Input argument, not modified.
+
+       Numeric must point to a valid Numeric object, computed by
+       umfpack_*_numeric.
+
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_solve.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_solve.h
new file mode 100644 (file)
index 0000000..d6a0a96
--- /dev/null
@@ -0,0 +1,302 @@
+/* ========================================================================== */
+/* === umfpack_solve ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_solve
+(
+    int sys,
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ],
+    double X [ ],
+    const double B [ ],
+    void *Numeric,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+long umfpack_dl_solve
+(
+    long sys,
+    const long Ap [ ],
+    const long Ai [ ],
+    const double Ax [ ],
+    double X [ ],
+    const double B [ ],
+    void *Numeric,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+int umfpack_zi_solve
+(
+    int sys,
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ], const double Az [ ],
+    double Xx [ ],      double Xz [ ],
+    const double Bx [ ], const double Bz [ ],
+    void *Numeric,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+long umfpack_zl_solve
+(
+    long sys,
+    const long Ap [ ],
+    const long Ai [ ],
+    const double Ax [ ], const double Az [ ],
+    double Xx [ ],      double Xz [ ],
+    const double Bx [ ], const double Bz [ ],
+    void *Numeric,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    int status, *Ap, *Ai, sys ;
+    double *B, *X, *Ax, Info [UMFPACK_INFO], Control [UMFPACK_CONTROL] ;
+    status = umfpack_di_solve (sys, Ap, Ai, Ax, X, B, Numeric, Control, Info) ;
+
+double long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    long status, *Ap, *Ai, sys ;
+    double *B, *X, *Ax, Info [UMFPACK_INFO], Control [UMFPACK_CONTROL] ;
+    status = umfpack_dl_solve (sys, Ap, Ai, Ax, X, B, Numeric, Control, Info) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    int status, *Ap, *Ai, sys ;
+    double *Bx, *Bz, *Xx, *Xz, *Ax, *Az, Info [UMFPACK_INFO],
+       Control [UMFPACK_CONTROL] ;
+    status = umfpack_zi_solve (sys, Ap, Ai, Ax, Az, Xx, Xz, Bx, Bz, Numeric,
+       Control, Info) ;
+
+complex long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    long status, *Ap, *Ai, sys ;
+    double *Bx, *Bz, *Xx, *Xz, *Ax, *Az, Info [UMFPACK_INFO],
+       Control [UMFPACK_CONTROL] ;
+    status = umfpack_zl_solve (sys, Ap, Ai, Ax, Az, Xx, Xz, Bx, Bz, Numeric,
+       Control, Info) ;
+
+Purpose:
+
+    Given LU factors computed by umfpack_*_numeric (PAQ=LU, PRAQ=LU, or
+    P(R\A)Q=LU) and the right-hand-side, B, solve a linear system for the
+    solution X.  Iterative refinement is optionally performed.  Only square
+    systems are handled.  Singular matrices result in a divide-by-zero for all
+    systems except those involving just the matrix L.  Iterative refinement is
+    not performed for singular matrices.  In the discussion below, n is equal
+    to n_row and n_col, because only square systems are handled.
+
+Returns:
+
+    The status code is returned.  See Info [UMFPACK_STATUS], below.
+
+Arguments:
+
+    Int sys ;          Input argument, not modified.
+
+       Defines which system to solve.  (') is the linear algebraic transpose
+       (complex conjugate if A is complex), and (.') is the array transpose.
+
+           sys value       system solved
+           UMFPACK_A       Ax=b
+           UMFPACK_At      A'x=b
+           UMFPACK_Aat     A.'x=b
+           UMFPACK_Pt_L    P'Lx=b
+           UMFPACK_L       Lx=b
+           UMFPACK_Lt_P    L'Px=b
+           UMFPACK_Lat_P   L.'Px=b
+           UMFPACK_Lt      L'x=b
+           UMFPACK_U_Qt    UQ'x=b
+           UMFPACK_U       Ux=b
+           UMFPACK_Q_Ut    QU'x=b
+           UMFPACK_Q_Uat   QU.'x=b
+           UMFPACK_Ut      U'x=b
+           UMFPACK_Uat     U.'x=b
+
+       Iterative refinement can be optionally performed when sys is any of
+       the following:
+
+           UMFPACK_A       Ax=b
+           UMFPACK_At      A'x=b
+           UMFPACK_Aat     A.'x=b
+
+       For the other values of the sys argument, iterative refinement is not
+       performed (Control [UMFPACK_IRSTEP], Ap, Ai, Ax, and Az are ignored).
+
+       Earlier versions used a string argument for sys.  It was changed to an
+       integer to make it easier for a Fortran code to call UMFPACK.
+
+    Int Ap [n+1] ;     Input argument, not modified.
+    Int Ai [nz] ;      Input argument, not modified.
+    double Ax [nz] ;   Input argument, not modified.
+    double Az [nz] ;   Input argument, not modified, for complex versions.
+
+       If iterative refinement is requested (Control [UMFPACK_IRSTEP] >= 1,
+       Ax=b, A'x=b, or A.'x=b is being solved, and A is nonsingular), then
+       these arrays must be identical to the same ones passed to
+       umfpack_*_numeric.  The umfpack_*_solve routine does not check the
+       contents of these arguments, so the results are undefined if Ap, Ai, Ax,
+       and/or Az are modified between the calls the umfpack_*_numeric and
+       umfpack_*_solve.  These three arrays do not need to be present (NULL
+       pointers can be passed) if Control [UMFPACK_IRSTEP] is zero, or if a
+       system other than Ax=b, A'x=b, or A.'x=b is being solved, or if A is
+       singular, since in each of these cases A is not accessed.
+
+       Future complex version:  if Ax is present and Az is NULL, then both real
+       and imaginary parts will be contained in Ax[0..2*nz-1], with Ax[2*k]
+       and Ax[2*k+1] being the real and imaginary part of the kth entry.
+
+    double X [n] ;     Output argument.
+    or:
+    double Xx [n] ;    Output argument, real part.
+    double Xz [n] ;    Output argument, imaginary part.
+
+       The solution to the linear system, where n = n_row = n_col is the
+       dimension of the matrices A, L, and U.
+
+       Future complex version:  if Xx is present and Xz is NULL, then both real
+       and imaginary parts will be returned in Xx[0..2*n-1], with Xx[2*k] and
+       Xx[2*k+1] being the real and imaginary part of the kth entry.
+
+    double B [n] ;     Input argument, not modified.
+    or:
+    double Bx [n] ;    Input argument, not modified, real part.
+    double Bz [n] ;    Input argument, not modified, imaginary part.
+
+       The right-hand side vector, b, stored as a conventional array of size n
+       (or two arrays of size n for complex versions).  This routine does not
+       solve for multiple right-hand-sides, nor does it allow b to be stored in
+       a sparse-column form.
+
+       Future complex version:  if Bx is present and Bz is NULL, then both real
+       and imaginary parts will be contained in Bx[0..2*n-1], with Bx[2*k]
+       and Bx[2*k+1] being the real and imaginary part of the kth entry.
+
+    void *Numeric ;            Input argument, not modified.
+
+       Numeric must point to a valid Numeric object, computed by
+       umfpack_*_numeric.
+
+    double Control [UMFPACK_CONTROL] ; Input argument, not modified.
+
+       If a (double *) NULL pointer is passed, then the default control
+       settings are used.  Otherwise, the settings are determined from the
+       Control array.  See umfpack_*_defaults on how to fill the Control
+       array with the default settings.  If Control contains NaN's, the
+       defaults are used.  The following Control parameters are used:
+
+       Control [UMFPACK_IRSTEP]:  The maximum number of iterative refinement
+           steps to attempt.  A value less than zero is treated as zero.  If
+           less than 1, or if Ax=b, A'x=b, or A.'x=b is not being solved, or
+           if A is singular, then the Ap, Ai, Ax, and Az arguments are not
+           accessed.  Default: 2.
+
+    double Info [UMFPACK_INFO] ;       Output argument.
+
+       Contains statistics about the solution factorization.  If a
+       (double *) NULL pointer is passed, then no statistics are returned in
+       Info (this is not an error condition).  The following statistics are
+       computed in umfpack_*_solve:
+
+       Info [UMFPACK_STATUS]: status code.  This is also the return value,
+           whether or not Info is present.
+
+           UMFPACK_OK
+
+               The linear system was successfully solved.
+
+           UMFPACK_WARNING_singular_matrix
+
+               A divide-by-zero occured.  Your solution will contain Inf's
+               and/or NaN's.  Some parts of the solution may be valid.  For
+               example, solving Ax=b with
+
+               A = [2 0]  b = [ 1 ]  returns x = [ 0.5 ]
+                   [0 0]      [ 0 ]              [ Inf ]
+
+           UMFPACK_ERROR_out_of_memory
+
+               Insufficient memory to solve the linear system.
+
+           UMFPACK_ERROR_argument_missing
+
+               One or more required arguments are missing.  The B, X, (or
+               Bx, Bz, Xx and Xz for the complex versions) arguments
+               are always required.  Info and Control are not required.  Ap,
+               Ai, Ax (and Az for complex versions) are required if Ax=b,
+               A'x=b, A.'x=b is to be solved, the (default) iterative
+               refinement is requested, and the matrix A is nonsingular.
+
+           UMFPACK_ERROR_invalid_system
+
+               The sys argument is not valid, or the matrix A is not square.
+
+           UMFPACK_ERROR_invalid_Numeric_object
+
+               The Numeric object is not valid.
+
+       Info [UMFPACK_NROW], Info [UMFPACK_NCOL]:
+               The dimensions of the matrix A (L is n_row-by-n_inner and
+               U is n_inner-by-n_col, with n_inner = min(n_row,n_col)).
+
+       Info [UMFPACK_NZ]:  the number of entries in the input matrix, Ap [n],
+           if iterative refinement is requested (Ax=b, A'x=b, or A.'x=b is
+           being solved, Control [UMFPACK_IRSTEP] >= 1, and A is nonsingular).
+
+       Info [UMFPACK_IR_TAKEN]:  The number of iterative refinement steps
+           effectively taken.  The number of steps attempted may be one more
+           than this; the refinement algorithm backtracks if the last
+           refinement step worsens the solution.
+
+       Info [UMFPACK_IR_ATTEMPTED]:   The number of iterative refinement steps
+           attempted.  The number of times a linear system was solved is one
+           more than this (once for the initial Ax=b, and once for each Ay=r
+           solved for each iterative refinement step attempted).
+
+       Info [UMFPACK_OMEGA1]:  sparse backward error estimate, omega1, if
+           iterative refinement was performed, or -1 if iterative refinement
+           not performed.
+
+       Info [UMFPACK_OMEGA2]:  sparse backward error estimate, omega2, if
+           iterative refinement was performed, or -1 if iterative refinement
+           not performed.
+
+       Info [UMFPACK_SOLVE_FLOPS]:  the number of floating point operations
+           performed to solve the linear system.  This includes the work
+           taken for all iterative refinement steps, including the backtrack
+           (if any).
+
+       Info [UMFPACK_SOLVE_TIME]:  The time taken, in seconds.
+
+       ------------------------------------------------------------------------
+       The following statistic was added to Version 4.1:
+       ------------------------------------------------------------------------
+
+        Info [UMFPACK_SOLVE_WALLTIME]:  The wallclock time taken, in seconds.
+
+       Only the above listed Info [...] entries are accessed.  The remaining
+       entries of Info are not accessed or modified by umfpack_*_solve.
+       Future versions might modify different parts of Info.
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_symbolic.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_symbolic.h
new file mode 100644 (file)
index 0000000..ed09ca5
--- /dev/null
@@ -0,0 +1,542 @@
+/* ========================================================================== */
+/* === umfpack_symbolic ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_symbolic
+(
+    int n_row,
+    int n_col,
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ],
+    void **Symbolic,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+long umfpack_dl_symbolic
+(
+    long n_row,
+    long n_col,
+    const long Ap [ ],
+    const long Ai [ ],
+    const double Ax [ ],
+    void **Symbolic,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+int umfpack_zi_symbolic
+(
+    int n_row,
+    int n_col,
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ], const double Az [ ],
+    void **Symbolic,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+long umfpack_zl_symbolic
+(
+    long n_row,
+    long n_col,
+    const long Ap [ ],
+    const long Ai [ ],
+    const double Ax [ ], const double Az [ ],
+    void **Symbolic,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    int n_row, n_col, *Ap, *Ai, status ;
+    double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax ;
+    status = umfpack_di_symbolic (n_row, n_col, Ap, Ai, Ax,
+       &Symbolic, Control, Info) ;
+
+double long Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    long n_row, n_col, *Ap, *Ai, status ;
+    double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax ;
+    status = umfpack_dl_symbolic (n_row, n_col, Ap, Ai, Ax,
+       &Symbolic, Control, Info) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    int n_row, n_col, *Ap, *Ai, status ;
+    double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax, *Az ;
+    status = umfpack_zi_symbolic (n_row, n_col, Ap, Ai, Ax, Az,
+       &Symbolic, Control, Info) ;
+
+complex long Syntax:
+
+    #include "umfpack.h"
+    void *Symbolic ;
+    long n_row, n_col, *Ap, *Ai, status ;
+    double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax, *Az ;
+    status = umfpack_zl_symbolic (n_row, n_col, Ap, Ai, Ax, Az,
+       &Symbolic, Control, Info) ;
+
+Purpose:
+
+    Given nonzero pattern of a sparse matrix A in column-oriented form,
+    umfpack_*_symbolic performs a column pre-ordering to reduce fill-in
+    (using COLAMD or AMD) and a symbolic factorization.  This is required
+    before the matrix can be numerically factorized with umfpack_*_numeric.
+    If you wish to bypass the COLAMD or AMD pre-ordering and provide your own
+    ordering, use umfpack_*_qsymbolic instead.
+
+    Since umfpack_*_symbolic and umfpack_*_qsymbolic are very similar, options
+    for both routines are discussed below.
+
+    For the following discussion, let S be the submatrix of A obtained after
+    eliminating all pivots of zero Markowitz cost.  S has dimension
+    (n_row-n1-nempty_row) -by- (n_col-n1-nempty_col), where
+    n1 = Info [UMFPACK_COL_SINGLETONS] + Info [UMFPACK_ROW_SINGLETONS],
+    nempty_row = Info [UMFPACK_NEMPTY_ROW] and
+    nempty_col = Info [UMFPACK_NEMPTY_COL].
+
+Returns:
+
+    The status code is returned.  See Info [UMFPACK_STATUS], below.
+
+Arguments:
+
+    Int n_row ;                Input argument, not modified.
+    Int n_col ;                Input argument, not modified.
+
+       A is an n_row-by-n_col matrix.  Restriction: n_row > 0 and n_col > 0.
+
+    Int Ap [n_col+1] ; Input argument, not modified.
+
+       Ap is an integer array of size n_col+1.  On input, it holds the
+       "pointers" for the column form of the sparse matrix A.  Column j of
+       the matrix A is held in Ai [(Ap [j]) ... (Ap [j+1]-1)].  The first
+       entry, Ap [0], must be zero, and Ap [j] <= Ap [j+1] must hold for all
+       j in the range 0 to n_col-1.  The value nz = Ap [n_col] is thus the
+       total number of entries in the pattern of the matrix A.  nz must be
+       greater than or equal to zero.
+
+    Int Ai [nz] ;      Input argument, not modified, of size nz = Ap [n_col].
+
+       The nonzero pattern (row indices) for column j is stored in
+       Ai [(Ap [j]) ... (Ap [j+1]-1)].  The row indices in a given column j
+       must be in ascending order, and no duplicate row indices may be present.
+       Row indices must be in the range 0 to n_row-1 (the matrix is 0-based).
+       See umfpack_*_triplet_to_col for how to sort the columns of a matrix
+       and sum up the duplicate entries.  See umfpack_*_report_matrix for how
+       to print the matrix A.
+
+    double Ax [nz] ;   Optional input argument, not modified.
+
+       The numerical values of the sparse matrix A.  The nonzero pattern (row
+       indices) for column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)], and
+       the corresponding numerical values are stored in
+       Ax [(Ap [j]) ... (Ap [j+1]-1)].  Used only by the 2-by-2 strategy to
+       determine whether entries are "large" or "small".  You do not have to
+       pass the same numerical values to umfpack_*_numeric.  If Ax is not
+       present (a (double *) NULL pointer), then any entry in A is assumed to
+       be "large".
+
+    double Az [nz] ;   Optional input argument, not modified, for complex
+                       versions.
+
+       For the complex versions, this holds the imaginary part of A.  The
+       imaginary part of column j is held in Az [(Ap [j]) ... (Ap [j+1]-1)].
+
+       Future complex version:  if Ax is present and Az is NULL, then both real
+       and imaginary parts will be contained in Ax[0..2*nz-1], with Ax[2*k]
+       and Ax[2*k+1] being the real and imaginary part of the kth entry.
+
+       Used by the 2-by-2 strategy only.  See the description of Ax, above.
+
+    void **Symbolic ;  Output argument.
+
+       **Symbolic is the address of a (void *) pointer variable in the user's
+       calling routine (see Syntax, above).  On input, the contents of this
+       variable are not defined.  On output, this variable holds a (void *)
+       pointer to the Symbolic object (if successful), or (void *) NULL if
+       a failure occurred.
+
+    double Control [UMFPACK_CONTROL] ; Input argument, not modified.
+
+       If a (double *) NULL pointer is passed, then the default control
+       settings are used (the defaults are suitable for all matrices,
+       ranging from those with highly unsymmetric nonzero pattern, to
+       symmetric matrices).  Otherwise, the settings are determined from the
+       Control array.  See umfpack_*_defaults on how to fill the Control
+       array with the default settings.  If Control contains NaN's, the
+       defaults are used.  The following Control parameters are used:
+
+       Control [UMFPACK_STRATEGY]:  This is the most important control
+           parameter.  It determines what kind of ordering and pivoting
+           strategy that UMFPACK should use.  It is new to Version 4.1
+           There are 4 options:
+
+           UMFPACK_STRATEGY_AUTO:  This is the default.  The input matrix is
+               analyzed to determine how symmetric the nonzero pattern is, and
+               how many entries there are on the diagonal.  It then selects one
+               of the following strategies.  Refer to the User Guide for a
+               description of how the strategy is automatically selected.
+
+           UMFPACK_STRATEGY_UNSYMMETRIC:  Use the unsymmetric strategy.  COLAMD
+               is used to order the columns of A, followed by a postorder of
+               the column elimination tree.  No attempt is made to perform
+               diagonal pivoting.  The column ordering is refined during
+               factorization.  This strategy was the only one provided with
+               UMFPACK V4.0.
+
+               In the numerical factorization, the
+               Control [UMFPACK_SYM_PIVOT_TOLERANCE] parameter is ignored.  A
+               pivot is selected if its magnitude is >=
+               Control [UMFPACK_PIVOT_TOLERANCE] (default 0.1) times the
+               largest entry in its column.
+
+           UMFPACK_STRATEGY_SYMMETRIC:  Use the symmetric strategy (new to
+               Version 4.1).  In this method, the approximate minimum degree
+               ordering (AMD) is applied to A+A', followed by a postorder of
+               the elimination tree of A+A'.  UMFPACK attempts to perform
+               diagonal pivoting during numerical factorization.  No refinement
+               of the column pre-ordering is performed during factorization.
+
+               In the numerical factorization, a nonzero entry on the diagonal
+               is selected as the pivot if its magnitude is >= Control
+               [UMFPACK_SYM_PIVOT_TOLERANCE] (default 0.001) times the largest
+               entry in its column.  If this is not acceptable, then an
+               off-diagonal pivot is selected with magnitude >= Control
+               [UMFPACK_PIVOT_TOLERANCE] (default 0.1) times the largest entry
+               in its column.
+
+           UMFPACK_STRATEGY_2BY2:  a row permutation P2 is found that places
+               large entries on the diagonal.  The matrix P2*A is then
+               factorized using the symmetric strategy, described above.
+               Refer to the User Guide for more information.
+
+       Control [UMFPACK_DENSE_COL]:
+           If COLAMD is used, columns with more than
+           max (16, Control [UMFPACK_DENSE_COL] * 16 * sqrt (n_row)) entries
+           are placed placed last in the column pre-ordering.  Default: 0.2.
+
+       Control [UMFPACK_DENSE_ROW]:
+           Rows with more than max (16, Control [UMFPACK_DENSE_ROW] * 16 *
+           sqrt (n_col)) entries are treated differently in the COLAMD
+           pre-ordering, and in the internal data structures during the
+           subsequent numeric factorization.  Default: 0.2.
+
+       Control [UMFPACK_AMD_DENSE]:  rows/columns in A+A' with more than
+           max (16, Control [UMFPACK_AMD_DENSE] * sqrt (n)) entries
+           (where n = n_row = n_col) are ignored in the AMD pre-ordering.
+           Default: 10.
+
+       Control [UMFPACK_BLOCK_SIZE]:  the block size to use for Level-3 BLAS
+           in the subsequent numerical factorization (umfpack_*_numeric).
+           A value less than 1 is treated as 1.  Default: 32.  Modifying this
+           parameter affects when updates are applied to the working frontal
+           matrix, and can indirectly affect fill-in and operation count.
+           As long as the block size is large enough (8 or so), this parameter
+           has a modest effect on performance. 
+
+       Control [UMFPACK_2BY2_TOLERANCE]:  a diagonal entry S (k,k) is
+           considered "small" if it is < tol * max (abs (S (:,k))), where S a
+           submatrix of the scaled input matrix, with pivots of zero Markowitz
+           cost removed.
+
+       Control [UMFPACK_SCALE]:  This parameter is new to V4.1.  See
+           umfpack_numeric.h for a description.  Only affects the 2-by-2
+           strategy.  Default: UMFPACK_SCALE_SUM.
+
+       Control [UMFPACK_FIXQ]:  If > 0, then the pre-ordering Q is not modified
+           during numeric factorization.  If < 0, then Q may be modified.  If
+           zero, then this is controlled automatically (the unsymmetric
+           strategy modifies Q, the others do not).  Default: 0.
+
+       Control [UMFPACK_AGGRESSIVE]:  If nonzero, aggressive absorption is used
+           in COLAMD and AMD.  Default: 1.
+
+    double Info [UMFPACK_INFO] ;       Output argument, not defined on input.
+
+       Contains statistics about the symbolic analysis.  If a (double *) NULL
+       pointer is passed, then no statistics are returned in Info (this is not
+       an error condition).  The entire Info array is cleared (all entries set
+       to -1) and then the following statistics are computed:
+
+       Info [UMFPACK_STATUS]: status code.  This is also the return value,
+           whether or not Info is present.
+
+           UMFPACK_OK
+
+               Each column of the input matrix contained row indices
+               in increasing order, with no duplicates.  Only in this case
+               does umfpack_*_symbolic compute a valid symbolic factorization.
+               For the other cases below, no Symbolic object is created
+               (*Symbolic is (void *) NULL).
+
+           UMFPACK_ERROR_n_nonpositive
+
+               n is less than or equal to zero.
+
+           UMFPACK_ERROR_invalid_matrix
+
+               Number of entries in the matrix is negative, Ap [0] is nonzero,
+               a column has a negative number of entries, a row index is out of
+               bounds, or the columns of input matrix were jumbled (unsorted
+               columns or duplicate entries).
+
+           UMFPACK_ERROR_out_of_memory
+
+               Insufficient memory to perform the symbolic analysis.  If the
+               analysis requires more than 2GB of memory and you are using
+               the 32-bit ("int") version of UMFPACK, then you are guaranteed
+               to run out of memory.  Try using the 64-bit version of UMFPACK.
+
+           UMFPACK_ERROR_argument_missing
+
+               One or more required arguments is missing.
+
+           UMFPACK_ERROR_internal_error
+
+               Something very serious went wrong.  This is a bug.
+               Please contact the author (davis@cise.ufl.edu).
+
+           Note that the UMFPACK_ERROR_problem_too_large error code is no
+           longer returned (it was in Version 4.0).
+
+       Info [UMFPACK_NROW]:  the value of the input argument n_row.
+
+       Info [UMFPACK_NCOL]:  the value of the input argument n_col.
+
+       Info [UMFPACK_NZ]:  the number of entries in the input matrix
+           (Ap [n_col]).
+
+       Info [UMFPACK_SIZE_OF_UNIT]:  the number of bytes in a Unit,
+           for memory usage statistics below.
+
+       Info [UMFPACK_SIZE_OF_INT]:  the number of bytes in an int.
+
+       Info [UMFPACK_SIZE_OF_LONG]:  the number of bytes in a long.
+
+       Info [UMFPACK_SIZE_OF_POINTER]:  the number of bytes in a void *
+           pointer.
+
+       Info [UMFPACK_SIZE_OF_ENTRY]:  the number of bytes in a numerical entry.
+
+       Info [UMFPACK_NDENSE_ROW]:  number of "dense" rows in A.  These rows are
+           ignored when the column pre-ordering is computed in COLAMD.  They
+           are also treated differently during numeric factorization.  If > 0,
+           then the matrix had to be re-analyzed by UMF_analyze, which does
+           not ignore these rows.
+
+       Info [UMFPACK_NEMPTY_ROW]:  number of "empty" rows in A, as determined
+           These are rows that either have no entries, or whose entries are
+           all in pivot columns of zero-Markowitz-cost pivots.
+
+       Info [UMFPACK_NDENSE_COL]:  number of "dense" columns in A.  COLAMD
+           orders these columns are ordered last in the factorization, but
+           before "empty" columns.
+
+       Info [UMFPACK_NEMPTY_COL]:  number of "empty" columns in A.  These are
+           columns that either have no entries, or whose entries are all in
+           pivot rows of zero-Markowitz-cost pivots.  These columns are
+           ordered last in the factorization, to the right of "dense" columns.
+
+       Info [UMFPACK_SYMBOLIC_DEFRAG]:  number of garbage collections
+           performed during ordering and symbolic pre-analysis.
+
+       Info [UMFPACK_SYMBOLIC_PEAK_MEMORY]:  the amount of memory (in Units)
+           required for umfpack_*_symbolic to complete.  This count includes
+           the size of the Symbolic object itself, which is also reported in
+           Info [UMFPACK_SYMBOLIC_SIZE].
+
+       Info [UMFPACK_SYMBOLIC_SIZE]: the final size of the Symbolic object (in
+           Units).  This is fairly small, roughly 2*n to 13*n integers,
+           depending on the matrix.
+
+       Info [UMFPACK_VARIABLE_INIT_ESTIMATE]: the Numeric object contains two
+           parts.  The first is fixed in size (O (n_row+n_col)).  The
+           second part holds the sparse LU factors and the contribution blocks
+           from factorized frontal matrices.  This part changes in size during
+           factorization.  Info [UMFPACK_VARIABLE_INIT_ESTIMATE] is the exact
+           size (in Units) required for this second variable-sized part in
+           order for the numerical factorization to start.
+
+       Info [UMFPACK_VARIABLE_PEAK_ESTIMATE]: the estimated peak size (in
+           Units) of the variable-sized part of the Numeric object.  This is
+           usually an upper bound, but that is not guaranteed. 
+
+       Info [UMFPACK_VARIABLE_FINAL_ESTIMATE]: the estimated final size (in
+           Units) of the variable-sized part of the Numeric object.  This is
+           usually an upper bound, but that is not guaranteed.  It holds just
+           the sparse LU factors.
+
+       Info [UMFPACK_NUMERIC_SIZE_ESTIMATE]:  an estimate of the final size (in
+           Units) of the entire Numeric object (both fixed-size and variable-
+           sized parts), which holds the LU factorization (including the L, U,
+           P and Q matrices).
+
+       Info [UMFPACK_PEAK_MEMORY_ESTIMATE]:  an estimate of the total amount of
+           memory (in Units) required by umfpack_*_symbolic and
+           umfpack_*_numeric to perform both the symbolic and numeric
+           factorization.  This is the larger of the amount of memory needed
+           in umfpack_*_numeric itself, and the amount of memory needed in
+           umfpack_*_symbolic (Info [UMFPACK_SYMBOLIC_PEAK_MEMORY]).  The
+           count includes the size of both the Symbolic and Numeric objects
+           themselves.  It can be a very loose upper bound, particularly when
+           the symmetric or 2-by-2 strategies are used.
+
+       Info [UMFPACK_FLOPS_ESTIMATE]:  an estimate of the total floating-point
+           operations required to factorize the matrix.  This is a "true"
+           theoretical estimate of the number of flops that would be performed
+           by a flop-parsimonious sparse LU algorithm.  It assumes that no
+           extra flops are performed except for what is strictly required to
+           compute the LU factorization.  It ignores, for example, the flops
+            performed by umfpack_di_numeric to add contribution blocks of
+           frontal matrices together.  If L and U are the upper bound on the
+           pattern of the factors, then this flop count estimate can be
+           represented in MATLAB (for real matrices, not complex) as:
+
+               Lnz = full (sum (spones (L))) - 1 ;     % nz in each col of L
+               Unz = full (sum (spones (U')))' - 1 ;   % nz in each row of U
+               flops = 2*Lnz*Unz + sum (Lnz) ;
+
+           The actual "true flop" count found by umfpack_*_numeric will be
+           less than this estimate.
+
+           For the real version, only (+ - * /) are counted.  For the complex
+           version, the following counts are used:
+
+               operation       flops
+               c = 1/b         6
+               c = a*b         6
+               c -= a*b        8
+
+       Info [UMFPACK_LNZ_ESTIMATE]:  an estimate of the number of nonzeros in
+           L, including the diagonal.  Since L is unit-diagonal, the diagonal
+           of L is not stored.  This estimate is a strict upper bound on the
+           actual nonzeros in L to be computed by umfpack_*_numeric.
+
+       Info [UMFPACK_UNZ_ESTIMATE]:  an estimate of the number of nonzeros in
+           U, including the diagonal.  This estimate is a strict upper bound on
+           the actual nonzeros in U to be computed by umfpack_*_numeric.
+
+       Info [UMFPACK_MAX_FRONT_SIZE_ESTIMATE]: estimate of the size of the
+           largest frontal matrix (# of entries), for arbitrary partial
+           pivoting during numerical factorization.
+
+       Info [UMFPACK_SYMBOLIC_TIME]:  The CPU time taken, in seconds.
+
+       ------------------------------------------------------------------------
+       The rest of the statistics are new to Version 4.1:
+       ------------------------------------------------------------------------
+
+       Info [UMFPACK_SYMBOLIC_WALLTIME]:  The wallclock time taken, in seconds.
+
+       Info [UMFPACK_STRATEGY_USED]: The ordering strategy used:
+           UMFPACK_STRATEGY_SYMMETRIC, UMFPACK_STRATEGY_UNSYMMETRIC, or
+           UMFPACK_STRATEGY_2BY2.
+
+       Info [UMFPACK_ORDERING_USED]:  The ordering method used:
+           UMFPACK_ORDERING_COLAMD or UMFPACK_ORDERING_AMD.  It can be
+           UMFPACK_ORDERING_GIVEN for umfpack_*_qsymbolic.
+
+       Info [UMFPACK_QFIXED]: 1 if the column pre-ordering will be refined
+           during numerical factorization, 0 if not.
+
+       Info [UMFPACK_DIAG_PREFERED]: 1 if diagonal pivoting will be attempted,
+           0 if not.
+
+       Info [UMFPACK_COL_SINGLETONS]:  the matrix A is analyzed by first
+           eliminating all pivots with zero Markowitz cost.  This count is the
+           number of these pivots with exactly one nonzero in their pivot
+           column.
+
+       Info [UMFPACK_ROW_SINGLETONS]:  the number of zero-Markowitz-cost
+           pivots with exactly one nonzero in their pivot row.
+
+       Info [UMFPACK_PATTERN_SYMMETRY]: the symmetry of the pattern of S.
+
+       Info [UMFPACK_NZ_A_PLUS_AT]: the number of off-diagonal entries in S+S'.
+
+       Info [UMFPACK_NZDIAG]:  the number of entries on the diagonal of S.
+
+       Info [UMFPACK_N2]:  if S is square, and nempty_row = nempty_col, this
+           is equal to n_row - n1 - nempty_row.
+
+       Info [UMFPACK_S_SYMMETRIC]: 1 if S is square and its diagonal has been
+           preserved, 0 otherwise.
+
+
+       Info [UMFPACK_MAX_FRONT_NROWS_ESTIMATE]: estimate of the max number of
+           rows in any frontal matrix, for arbitrary partial pivoting.
+
+       Info [UMFPACK_MAX_FRONT_NCOLS_ESTIMATE]: estimate of the max number of
+           columns in any frontal matrix, for arbitrary partial pivoting.
+
+       ------------------------------------------------------------------------
+       The next four statistics are computed only if AMD is used:
+       ------------------------------------------------------------------------
+
+       Info [UMFPACK_SYMMETRIC_LUNZ]: The number of nonzeros in L and U,
+           assuming no pivoting during numerical factorization, and assuming a
+           zero-free diagonal of U.  Excludes the entries on the diagonal of
+           L.  If the matrix has a purely symmetric nonzero pattern, this is
+           often a lower bound on the nonzeros in the actual L and U computed
+           in the numerical factorization, for matrices that fit the criteria
+           for the "symmetric" strategy.
+
+       Info [UMFPACK_SYMMETRIC_FLOPS]: The floating-point operation count in
+           the numerical factorization phase, assuming no pivoting.  If the
+           pattern of the matrix is symmetric, this is normally a lower bound
+           on the floating-point operation count in the actual numerical
+           factorization, for matrices that fit the criteria for the symmetric
+           or 2-by-2 strategies
+
+       Info [UMFPACK_SYMMETRIC_NDENSE]: The number of "dense" rows/columns of
+           S+S' that were ignored during the AMD ordering.  These are placed
+           last in the output order.  If > 0, then the
+           Info [UMFPACK_SYMMETRIC_*] statistics, above are rough upper bounds.
+
+       Info [UMFPACK_SYMMETRIC_DMAX]: The maximum number of nonzeros in any
+           column of L, if no pivoting is performed during numerical
+           factorization.  Excludes the part of the LU factorization for
+           pivots with zero Markowitz cost.
+
+       ------------------------------------------------------------------------
+       The following statistics are computed only if the 2-by-2 strategy is
+       used or attempted:
+       ------------------------------------------------------------------------
+
+       Info [UMFPACK_2BY2_NWEAK]: the number of small diagonal entries in S.
+
+       Info [UMFPACK_2BY2_UNMATCHED]: the number of small diagonal entries
+           in P2*S.
+
+       Info [UMFPACK_2BY2_PATTERN_SYMMETRY]: the symmetry of P2*S.
+
+       Info [UMFPACK_2BY2_NZ_PA_PLUS_AT]:  the number of off-diagonal entries
+           in (P2*S)+(P2*S)'.
+
+       Info [UMFPACK_2BY2_NZDIAG]:  the number of nonzero entries on the
+           diagonal of P2*S.
+
+
+       At the start of umfpack_*_symbolic, all of Info is set of -1, and then
+       after that only the above listed Info [...] entries are accessed.
+       Future versions might modify different parts of Info.
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_tictoc.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_tictoc.h
new file mode 100644 (file)
index 0000000..550d7d5
--- /dev/null
@@ -0,0 +1,61 @@
+/* ========================================================================== */
+/* === umfpack_tictoc ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+void umfpack_tic (double stats [2]) ;
+
+void umfpack_toc (double stats [2]) ;
+
+
+/*
+Syntax (for all versions: di, dl, zi, and zl):
+
+    #include "umfpack.h"
+    double stats [2] ;
+    umfpack_tic (stats) ;
+    ...
+    umfpack_toc (stats) ;
+
+Purpose:
+
+    umfpack_tic returns the CPU time and wall clock time used by the process.
+    The CPU time includes both "user" and "system" time (the latter is time
+    spent by the system on behalf of the process, and is thus charged to the
+    process).  umfpack_toc returns the CPU time and wall clock time since the
+    last call to umfpack_tic with the same stats array.
+
+    Typical usage:
+
+       umfpack_tic (stats) ;
+       ... do some work ...
+       umfpack_toc (stats) ;
+
+    then stats [1] contains the time in seconds used by the code between
+    umfpack_tic and umfpack_toc, and stats [0] contains the wall clock time
+    elapsed between the umfpack_tic and umfpack_toc.  These two routines act
+    just like tic and toc in MATLAB, except that the both process time and
+    wall clock time are returned.
+
+    This routine normally uses the sysconf and times routines in the POSIX
+    standard.  If -DNPOSIX is defined at compile time, then the ANSI C clock
+    routine is used instead, and only the CPU time is returned (stats [0]
+    is set to zero).
+
+    umfpack_tic and umfpack_toc are the routines used internally in UMFPACK
+    to time the symbolic analysis, numerical factorization, and the forward/
+    backward solve.
+
+Arguments:
+
+    double stats [2]:
+
+       stats [0]:  wall clock time, in seconds
+       stats [1]:  CPU time, in seconds
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_timer.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_timer.h
new file mode 100644 (file)
index 0000000..a29c2f4
--- /dev/null
@@ -0,0 +1,41 @@
+/* ========================================================================== */
+/* === umfpack_timer ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+double umfpack_timer ( void ) ;
+
+/*
+Syntax (for all versions: di, dl, zi, and zl):
+
+    #include "umfpack.h"
+    double t ;
+    t = umfpack_timer ( ) ;
+
+Purpose:
+
+    Returns the CPU time used by the process.  Includes both "user" and "system"
+    time (the latter is time spent by the system on behalf of the process, and
+    is thus charged to the process).  It does not return the wall clock time.
+    This was the timer used internally in UMFPACK V4.0.  See umfpack_tic and
+    umfpack_toc (the file umfpack_tictoc.h) for the timer used internally by
+    UMFPACK V4.1.
+
+    This routine uses the Unix getrusage routine, if available.  It is less
+    subject to overflow than the ANSI C clock routine.  If getrusage is not
+    available, the portable ANSI C clock routine is used instead.
+    Unfortunately, clock ( ) overflows if the CPU time exceeds 2147 seconds
+    (about 36 minutes) when sizeof (clock_t) is 4 bytes.  If you have getrusage,
+    be sure to compile UMFPACK with the -DGETRUSAGE flag set; see umf_config.h
+    and the User Guide for details.  Even the getrusage routine can overlow.
+
+Arguments:
+
+    None.
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_transpose.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_transpose.h
new file mode 100644 (file)
index 0000000..f9d34cb
--- /dev/null
@@ -0,0 +1,217 @@
+/* ========================================================================== */
+/* === umfpack_transpose ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_transpose
+(
+    int n_row,
+    int n_col,
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ],
+    const int P [ ],
+    const int Q [ ],
+    int Rp [ ],
+    int Ri [ ],
+    double Rx [ ]
+) ;
+
+long umfpack_dl_transpose
+(
+    long n_row,
+    long n_col,
+    const long Ap [ ],
+    const long Ai [ ],
+    const double Ax [ ],
+    const long P [ ],
+    const long Q [ ],
+    long Rp [ ],
+    long Ri [ ],
+    double Rx [ ]
+) ;
+
+int umfpack_zi_transpose
+(
+    int n_row,
+    int n_col,
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ], const double Az [ ],
+    const int P [ ],
+    const int Q [ ],
+    int Rp [ ],
+    int Ri [ ],
+    double Rx [ ], double Rz [ ],
+    int do_conjugate
+) ;
+
+long umfpack_zl_transpose
+(
+    long n_row,
+    long n_col,
+    const long Ap [ ],
+    const long Ai [ ],
+    const double Ax [ ], const double Az [ ],
+    const long P [ ],
+    const long Q [ ],
+    long Rp [ ],
+    long Ri [ ],
+    double Rx [ ], double Rz [ ],
+    long do_conjugate
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    int n_row, n_col, status, *Ap, *Ai, *P, *Q, *Rp, *Ri ;
+    double *Ax, *Rx ;
+    status = umfpack_di_transpose (n_row, n_col, Ap, Ai, Ax, P, Q, Rp, Ri, Rx) ;
+
+double long Syntax:
+
+    #include "umfpack.h"
+    long n_row, n_col, status, *Ap, *Ai, *P, *Q, *Rp, *Ri ;
+    double *Ax, *Rx ;
+    status = umfpack_dl_transpose (n_row, n_col, Ap, Ai, Ax, P, Q, Rp, Ri, Rx) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    int n_row, n_col, status, *Ap, *Ai, *P, *Q, *Rp, *Ri, do_conjugate ;
+    double *Ax, *Az, *Rx, *Rz ;
+    status = umfpack_zi_transpose (n_row, n_col, Ap, Ai, Ax, Az, P, Q,
+       Rp, Ri, Rx, Rz, do_conjugate) ;
+
+complex long Syntax:
+
+    #include "umfpack.h"
+    long n_row, n_col, status, *Ap, *Ai, *P, *Q, *Rp, *Ri, do_conjugate ;
+    double *Ax, *Az, *Rx, *Rz ;
+    status = umfpack_zl_transpose (n_row, n_col, Ap, Ai, Ax, Az, P, Q,
+       Rp, Ri, Rx, Rz, do_conjugate) ;
+
+Purpose:
+
+    Transposes and optionally permutes a sparse matrix in row or column-form,
+    R = (PAQ)'.  In MATLAB notation, R = (A (P,Q))' or R = (A (P,Q)).' doing
+    either the linear algebraic transpose or the array transpose. Alternatively,
+    this routine can be viewed as converting A (P,Q) from column-form to
+    row-form, or visa versa (for the array transpose).  Empty rows and columns
+    may exist.  The matrix A may be singular and/or rectangular.
+
+    umfpack_*_transpose is useful if you want to factorize A' or A.' instead of
+    A.  Factorizing A' or A.' instead of A can be much better, particularly if
+    AA' is much sparser than A'A.  You can still solve Ax=b if you factorize
+    A' or A.', by solving with the sys argument UMFPACK_At or UMFPACK_Aat,
+    respectively, in umfpack_*_*solve.  The umfpack mexFunction (umfpackmex.c)
+    is one example.  To compute x = A/b, it computes x = (A.'\b.').' instead,
+    by factorizing A.'.  It then uses the regular solve, since b.' and x.' are
+    stored identically as b and x, respectively (both b.' and b are dense
+    vectors).  If b and x were arrays, the umfpack mexFunction would need to
+    first compute b.' and then transpose the resulting solution.
+
+Returns:
+
+    UMFPACK_OK if successful.
+    UMFPACK_ERROR_out_of_memory if umfpack_*_transpose fails to allocate a
+       size-max (n_row,n_col) workspace.
+    UMFPACK_ERROR_argument_missing if Ai, Ap, Ri, and/or Rp are missing.
+    UMFPACK_ERROR_n_nonpositive if n_row <= 0 or n_col <= 0
+    UMFPACK_ERROR_invalid_permutation if P and/or Q are invalid.
+    UMFPACK_ERROR_invalid_matrix if Ap [n_col] < 0, if Ap [0] != 0,
+       if Ap [j] > Ap [j+1] for any j in the range 0 to n_col-1,
+       if any row index i is < 0 or >= n_row, or if the row indices
+       in any column are not in ascending order.
+
+Arguments:
+
+    Int n_row ;                Input argument, not modified.
+    Int n_col ;                Input argument, not modified.
+
+       A is an n_row-by-n_col matrix.  Restriction: n_row > 0 and n_col > 0.
+
+    Int Ap [n_col+1] ; Input argument, not modified.
+
+       The column pointers of the column-oriented form of the matrix A.  See
+       umfpack_*_symbolic for a description.  The number of entries in
+       the matrix is nz = Ap [n_col].  Ap [0] must be zero, Ap [n_col] must be
+       => 0, and Ap [j] <= Ap [j+1] and Ap [j] <= Ap [n_col] must be true for
+       all j in the range 0 to n_col-1.  Empty columns are OK (that is, Ap [j]
+       may equal Ap [j+1] for any j in the range 0 to n_col-1).
+
+    Int Ai [nz] ;      Input argument, not modified, of size nz = Ap [n_col].
+
+       The nonzero pattern (row indices) for column j is stored in
+       Ai [(Ap [j]) ... (Ap [j+1]-1)].  The row indices in a given column j
+       must be in ascending order, and no duplicate row indices may be present.
+       Row indices must be in the range 0 to n_row-1 (the matrix is 0-based).
+
+    double Ax [nz] ;   Input argument, not modified, of size nz = Ap [n_col].
+    double Az [nz] ;   Input argument, not modified, for complex versions.
+
+       If present, these are the numerical values of the sparse matrix A.
+       The nonzero pattern (row indices) for column j is stored in
+       Ai [(Ap [j]) ... (Ap [j+1]-1)], and the corresponding real numerical
+       values are stored in Ax [(Ap [j]) ... (Ap [j+1]-1)].  The imaginary
+       values are stored in Az [(Ap [j]) ... (Ap [j+1]-1)].  The values are
+       transposed only if Ax and Rx are present (for the real version), and
+       only if all four (Ax, Az, Rx, and Rz) are present for the complex
+       version.  These are not an error conditions; you are able to transpose
+       and permute just the pattern of a matrix.
+
+       Future complex version:  if Ax is present and Az is NULL, then both real
+       and imaginary parts will be contained in Ax[0..2*nz-1], with Ax[2*k]
+       and Ax[2*k+1] being the real and imaginary part of the kth entry.
+
+    Int P [n_row] ;            Input argument, not modified.
+
+       The permutation vector P is defined as P [k] = i, where the original
+       row i of A is the kth row of PAQ.  If you want to use the identity
+       permutation for P, simply pass (Int *) NULL for P.  This is not an error
+       condition.  P is a complete permutation of all the rows of A; this
+       routine does not support the creation of a transposed submatrix of A
+       (R = A (1:3,:)' where A has more than 3 rows, for example, cannot be
+       done; a future version might support this operation).
+
+    Int Q [n_col] ;            Input argument, not modified.
+
+       The permutation vector Q is defined as Q [k] = j, where the original
+       column j of A is the kth column of PAQ.  If you want to use the identity
+       permutation for Q, simply pass (Int *) NULL for Q.  This is not an error
+       condition.  Q is a complete permutation of all the columns of A; this
+       routine does not support the creation of a transposed submatrix of A.
+
+    Int Rp [n_row+1] ; Output argument.
+
+       The column pointers of the matrix R = (A (P,Q))' or (A (P,Q)).', in the
+       same form as the column pointers Ap for the matrix A.
+
+    Int Ri [nz] ;      Output argument.
+
+       The row indices of the matrix R = (A (P,Q))' or (A (P,Q)).' , in the
+       same form as the row indices Ai for the matrix A.
+
+    double Rx [nz] ;   Output argument.
+    double Rz [nz] ;   Output argument, imaginary part for complex versions.
+
+       If present, these are the numerical values of the sparse matrix R,
+       in the same form as the values Ax and Az of the matrix A.
+
+       Future complex version:  if Rx is present and Rz is NULL, then both real
+       and imaginary parts will be contained in Rx[0..2*nz-1], with Rx[2*k]
+       and Rx[2*k+1] being the real and imaginary part of the kth entry.
+
+    Int do_conjugate ; Input argument for complex versions only.
+
+       If true, and if Ax, Az, Rx, and Rz are all present, then the linear
+       algebraic transpose is computed (complex conjugate).  If false, the
+       array transpose is computed instead.
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_triplet_to_col.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_triplet_to_col.h
new file mode 100644 (file)
index 0000000..ea55157
--- /dev/null
@@ -0,0 +1,261 @@
+/* ========================================================================== */
+/* === umfpack_triplet_to_col =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_triplet_to_col
+(
+    int n_row,
+    int n_col,
+    int nz,
+    const int Ti [ ],
+    const int Tj [ ],
+    const double Tx [ ],
+    int Ap [ ],
+    int Ai [ ],
+    double Ax [ ],
+    int Map [ ]
+) ;
+
+long umfpack_dl_triplet_to_col
+(
+    long n_row,
+    long n_col,
+    long nz,
+    const long Ti [ ],
+    const long Tj [ ],
+    const double Tx [ ],
+    long Ap [ ],
+    long Ai [ ],
+    double Ax [ ],
+    long Map [ ]
+) ;
+
+int umfpack_zi_triplet_to_col
+(
+    int n_row,
+    int n_col,
+    int nz,
+    const int Ti [ ],
+    const int Tj [ ],
+    const double Tx [ ], const double Tz [ ],
+    int Ap [ ],
+    int Ai [ ],
+    double Ax [ ], double Az [ ],
+    int Map [ ]
+) ;
+
+long umfpack_zl_triplet_to_col
+(
+    long n_row,
+    long n_col,
+    long nz,
+    const long Ti [ ],
+    const long Tj [ ],
+    const double Tx [ ], const double Tz [ ],
+    long Ap [ ],
+    long Ai [ ],
+    double Ax [ ], double Az [ ],
+    long Map [ ]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    int n_row, n_col, nz, *Ti, *Tj, *Ap, *Ai, status, *Map ;
+    double *Tx, *Ax ;
+    status = umfpack_di_triplet_to_col (n_row, n_col, nz, Ti, Tj, Tx,
+       Ap, Ai, Ax, Map) ;
+
+double long Syntax:
+
+    #include "umfpack.h"
+    long n_row, n_col, nz, *Ti, *Tj, *Ap, *Ai, status, *Map ;
+    double *Tx, *Ax ;
+    status = umfpack_dl_triplet_to_col (n_row, n_col, nz, Ti, Tj, Tx,
+       Ap, Ai, Ax, Map) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    int n_row, n_col, nz, *Ti, *Tj, *Ap, *Ai, status, *Map ;
+    double *Tx, *Tz, *Ax, *Az ;
+    status = umfpack_zi_triplet_to_col (n_row, n_col, nz, Ti, Tj, Tx, Tz,
+       Ap, Ai, Ax, Az, Map) ;
+
+long Syntax:
+
+    #include "umfpack.h"
+    long n_row, n_col, nz, *Ti, *Tj, *Ap, *Ai, status, *Map ;
+    double *Tx, *Tz, *Ax, *Az ;
+    status = umfpack_zl_triplet_to_col (n_row, n_col, nz, Ti, Tj, Tx, Tz,
+       Ap, Ai, Ax, Az, Map) ;
+
+Purpose:
+
+    Converts a sparse matrix from "triplet" form to compressed-column form.
+    Analogous to A = spconvert (Ti, Tj, Tx + Tx*1i) in MATLAB, except that
+    zero entries present in the triplet form are present in A.
+
+    The triplet form of a matrix is a very simple data structure for basic
+    sparse matrix operations.  For example, suppose you wish to factorize a
+    matrix A coming from a finite element method, in which A is a sum of
+    dense submatrices, A = E1 + E2 + E3 + ... .  The entries in each element
+    matrix Ei can be concatenated together in the three triplet arrays, and
+    any overlap between the elements will be correctly summed by
+    umfpack_*_triplet_to_col.
+
+    Transposing a matrix in triplet form is simple; just interchange the
+    use of Ti and Tj.  You can construct the complex conjugate transpose by
+    negating Tz, for the complex versions.
+
+    Permuting a matrix in triplet form is also simple.  If you want the matrix
+    PAQ, or A (P,Q) in MATLAB notation, where P [k] = i means that row i of
+    A is the kth row of PAQ and Q [k] = j means that column j of A is the kth
+    column of PAQ, then do the following.  First, create inverse permutations
+    Pinv and Qinv such that Pinv [i] = k if P [k] = i and Qinv [j] = k if
+    Q [k] = j.  Next, for the mth triplet (Ti [m], Tj [m], Tx [m], Tz [m]),
+    replace Ti [m] with Pinv [Ti [m]] and replace Tj [m] with Qinv [Tj [m]].
+
+    If you have a column-form matrix with duplicate entries or unsorted
+    columns, you can sort it and sum up the duplicates by first converting it
+    to triplet form with umfpack_*_col_to_triplet, and then converting it back
+    with umfpack_*_triplet_to_col.
+
+    Constructing a submatrix is also easy.  Just scan the triplets and remove
+    those entries outside the desired subset of 0...n_row-1 and 0...n_col-1,
+    and renumber the indices according to their position in the subset.
+
+    You can do all these operations on a column-form matrix by first
+    converting it to triplet form with umfpack_*_col_to_triplet, doing the
+    operation on the triplet form, and then converting it back with
+    umfpack_*_triplet_to_col.
+
+    The only operation not supported easily in the triplet form is the
+    multiplication of two sparse matrices (UMFPACK does not provide this
+    operation).
+
+    You can print the input triplet form with umfpack_*_report_triplet, and
+    the output matrix with umfpack_*_report_matrix.
+
+    The matrix may be singular (nz can be zero, and empty rows and/or columns
+    may exist).  It may also be rectangular and/or complex.
+
+Returns:
+
+    UMFPACK_OK if successful.
+    UMFPACK_ERROR_argument_missing if Ap, Ai, Ti, and/or Tj are missing.
+    UMFPACK_ERROR_n_nonpositive if n_row <= 0 or n_col <= 0.
+    UMFPACK_ERROR_invalid_matrix if nz < 0, or if for any k, Ti [k] and/or
+       Tj [k] are not in the range 0 to n_row-1 or 0 to n_col-1, respectively.
+    UMFPACK_ERROR_out_of_memory if unable to allocate sufficient workspace.
+
+Arguments:
+
+    Int n_row ;                Input argument, not modified.
+    Int n_col ;                Input argument, not modified.
+
+       A is an n_row-by-n_col matrix.  Restriction: n_row > 0 and n_col > 0.
+       All row and column indices in the triplet form must be in the range
+       0 to n_row-1 and 0 to n_col-1, respectively.
+
+    Int nz ;           Input argument, not modified.
+
+       The number of entries in the triplet form of the matrix.  Restriction:
+       nz >= 0.
+
+    Int Ti [nz] ;      Input argument, not modified.
+    Int Tj [nz] ;      Input argument, not modified.
+    double Tx [nz] ;   Input argument, not modified.
+    double Tz [nz] ;   Input argument, not modified, for complex versions.
+
+       Ti, Tj, Tx, and Tz hold the "triplet" form of a sparse matrix.  The kth
+       nonzero entry is in row i = Ti [k], column j = Tj [k], and the real part
+       of a_ij is Tx [k].  The imaginary part of a_ij is Tz [k], for complex
+       versions.  The row and column indices i and j must be in the range 0 to
+       n_row-1 and 0 to n_col-1, respectively.  Duplicate entries may be
+       present; they are summed in the output matrix.  This is not an error
+       condition.  The "triplets" may be in any order.  Tx, Tz, Ax, and Az
+       are optional.  For the real version, Ax is computed only if both Ax
+       and Tx are present (not (double *) NULL).  For the complex version, Ax
+       and Az are computed only if Tx, Tz, Ax, and Az are all present.  These
+       are not error conditions; the routine can create just the pattern of
+       the output matrix from the pattern of the triplets.
+
+       Future complex version:  if Tx is present and Tz is NULL, then both real
+       and imaginary parts will be contained in Tx[0..2*nz-1], with Tx[2*k]
+       and Tx[2*k+1] being the real and imaginary part of the kth entry.
+
+    Int Ap [n_col+1] ; Output argument.
+
+       Ap is an integer array of size n_col+1 on input.  On output, Ap holds
+       the "pointers" for the column form of the sparse matrix A.  Column j of
+       the matrix A is held in Ai [(Ap [j]) ... (Ap [j+1]-1)].  The first
+       entry, Ap [0], is zero, and Ap [j] <= Ap [j+1] holds for all j in the
+       range 0 to n_col-1.  The value nz2 = Ap [n_col] is thus the total
+       number of entries in the pattern of the matrix A.  Equivalently, the
+       number of duplicate triplets is nz - Ap [n_col].
+
+    Int Ai [nz] ;      Output argument.
+
+       Ai is an integer array of size nz on input.  Note that only the first
+       Ap [n_col] entries are used.
+
+       The nonzero pattern (row indices) for column j is stored in
+       Ai [(Ap [j]) ... (Ap [j+1]-1)].  The row indices in a given column j
+       are in ascending order, and no duplicate row indices are present.
+       Row indices are in the range 0 to n_col-1 (the matrix is 0-based).
+
+    double Ax [nz] ;   Output argument.
+    double Az [nz] ;   Output argument for complex versions.
+
+       Ax and Az (for the complex versions) are double arrays of size nz on
+       input.  Note that only the first Ap [n_col] entries are used
+       in both arrays.
+
+       Ax is optional; if Tx and/or Ax are not present (a (double *) NULL
+       pointer), then Ax is not computed.  Az is also optional; if Tz and/or
+       Az are not present, then Az is not computed.  If present, Ax holds the
+       numerical values of the the real part of the sparse matrix A and Az
+       holds the imaginary parts.  The nonzero pattern (row indices) for
+       column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)], and the
+       corresponding numerical values are stored in
+       Ax [(Ap [j]) ... (Ap [j+1]-1)].  The imaginary parts are stored in
+       Az [(Ap [j]) ... (Ap [j+1]-1)], for the complex versions.
+
+       Future complex version:  if Ax is present and Az is NULL, then both real
+       and imaginary parts will be returned in Ax[0..2*nz2-1], with Ax[2*k]
+       and Ax[2*k+1] being the real and imaginary part of the kth entry.
+
+    int Map [nz] ;     Optional output argument.
+
+       If Map is present (a non-NULL pointer to an Int array of size nz), then
+       on output it holds the position of the triplets in the column-form
+       matrix.  That is, suppose p = Map [k], and the k-th triplet is i=Ti[k],
+       j=Tj[k], and aij=Tx[k].  Then i=Ai[p], and aij will have been summed
+       into Ax[p] (or simply aij=Ax[p] if there were no duplicate entries also
+       in row i and column j).  Also, Ap[j] <= p < Ap[j+1].  The Map array is
+       not computed if it is (Int *) NULL.  The Map array is useful for
+       converting a subsequent triplet form matrix with the same pattern as the
+       first one, without calling this routine.  If Ti and Tj do not change,
+       then Ap, and Ai can be reused from the prior call to
+       umfpack_*_triplet_to_col.  You only need to recompute Ax (and Az for the
+       complex version).  This code excerpt properly sums up all duplicate
+       values (for the real version):
+
+           for (p = 0 ; p < Ap [n_col] ; p++) Ax [p] = 0 ;
+           for (k = 0 ; k < nz ; k++) Ax [Map [k]] += Tx [k] ;
+
+       This feature is useful (along with the reuse of the Symbolic object) if
+       you need to factorize a sequence of triplet matrices with identical
+       nonzero pattern (the order of the triplets in the Ti,Tj,Tx arrays must
+       also remain unchanged).  It is faster than calling this routine for
+       each matrix, and requires no workspace.
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_wsolve.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_wsolve.h
new file mode 100644 (file)
index 0000000..7eda906
--- /dev/null
@@ -0,0 +1,166 @@
+/* ========================================================================== */
+/* === umfpack_wsolve ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_wsolve
+(
+    int sys,
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ],
+    double X [ ],
+    const double B [ ],
+    void *Numeric,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO],
+    int Wi [ ],
+    double W [ ]
+) ;
+
+long umfpack_dl_wsolve
+(
+    long sys,
+    const long Ap [ ],
+    const long Ai [ ],
+    const double Ax [ ],
+    double X [ ],
+    const double B [ ],
+    void *Numeric,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO],
+    long Wi [ ],
+    double W [ ]
+) ;
+
+int umfpack_zi_wsolve
+(
+    int sys,
+    const int Ap [ ],
+    const int Ai [ ],
+    const double Ax [ ], const double Az [ ],
+    double Xx [ ],      double Xz [ ],
+    const double Bx [ ], const double Bz [ ],
+    void *Numeric,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO],
+    int Wi [ ],
+    double W [ ]
+) ;
+
+long umfpack_zl_wsolve
+(
+    long sys,
+    const long Ap [ ],
+    const long Ai [ ],
+    const double Ax [ ], const double Az [ ],
+    double Xx [ ],      double Xz [ ],
+    const double Bx [ ], const double Bz [ ],
+    void *Numeric,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO],
+    long Wi [ ],
+    double W [ ]
+) ;
+
+/*
+double int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    int status, *Ap, *Ai, *Wi, sys ;
+    double *B, *X, *Ax, *W, Info [UMFPACK_INFO], Control [UMFPACK_CONTROL] ;
+    status = umfpack_di_wsolve (sys, Ap, Ai, Ax, X, B, Numeric,
+       Control, Info, Wi, W) ;
+
+double long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    long status, *Ap, *Ai, *Wi, sys ;
+    double *B, *X, *Ax, *W, Info [UMFPACK_INFO], Control [UMFPACK_CONTROL] ;
+    status = umfpack_dl_wsolve (sys, Ap, Ai, Ax, X, B, Numeric,
+       Control, Info, Wi, W) ;
+
+complex int Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    int status, *Ap, *Ai, *Wi, sys ;
+    double *Bx, *Bz, *Xx, *Xz, *Ax, *Az, *W,
+       Info [UMFPACK_INFO], Control [UMFPACK_CONTROL] ;
+    status = umfpack_zi_wsolve (sys, Ap, Ai, Ax, Az, Xx, Xz, Bx, Bz, Numeric,
+       Control, Info, Wi, W) ;
+
+complex long Syntax:
+
+    #include "umfpack.h"
+    void *Numeric ;
+    long status, *Ap, *Ai, *Wi, sys ;
+    double *Bx, *Bz, *Xx, *Xz, *Ax, *Az, *W,
+       Info [UMFPACK_INFO], Control [UMFPACK_CONTROL] ;
+    status = umfpack_zl_wsolve (sys, Ap, Ai, Ax, Az, Xx, Xz, Bx, Bz, Numeric,
+       Control, Info, Wi, W) ;
+
+Purpose:
+
+    Given LU factors computed by umfpack_*_numeric (PAQ=LU) and the
+    right-hand-side, B, solve a linear system for the solution X.  Iterative
+    refinement is optionally performed.  This routine is identical to
+    umfpack_*_solve, except that it does not dynamically allocate any workspace.
+    When you have many linear systems to solve, this routine is faster than
+    umfpack_*_solve, since the workspace (Wi, W) needs to be allocated only
+    once, prior to calling umfpack_*_wsolve.
+
+Returns:
+
+    The status code is returned.  See Info [UMFPACK_STATUS], below.
+
+Arguments:
+
+    Int sys ;          Input argument, not modified.
+    Int Ap [n+1] ;     Input argument, not modified.
+    Int Ai [nz] ;      Input argument, not modified.
+    double Ax [nz] ;   Input argument, not modified.
+    double X [n] ;     Output argument.
+    double B [n] ;     Input argument, not modified.
+    void *Numeric ;    Input argument, not modified.
+    double Control [UMFPACK_CONTROL] ; Input argument, not modified.
+    double Info [UMFPACK_INFO] ;       Output argument.
+
+    for complex versions:
+    double Az [nz] ;   Input argument, not modified, imaginary part
+    double Xx [n] ;    Output argument, real part.
+    double Xz [n] ;    Output argument, imaginary part
+    double Bx [n] ;    Input argument, not modified, real part
+    double Bz [n] ;    Input argument, not modified, imaginary part
+
+       The above arguments are identical to umfpack_*_solve, except that the
+       error code UMFPACK_ERROR_out_of_memory will not be returned in
+       Info [UMFPACK_STATUS], since umfpack_*_wsolve does not allocate any
+       memory.
+
+    Int Wi [n] ;               Workspace.
+    double W [c*n] ;           Workspace, where c is defined below.
+
+       The Wi and W arguments are workspace used by umfpack_*_wsolve.  They
+       need not be initialized on input, and their contents are undefined on
+       output.  The size of W depends on whether or not iterative refinement is
+       used, and which version (real or complex) is called.  Iterative
+       refinement is performed if Ax=b, A'x=b, or A.'x=b is being solved,
+       Control [UMFPACK_IRSTEP] > 0, and A is nonsingular.  The size of W is
+       given below:
+
+                               no iter.        with iter.
+                               refinement      refinement
+       umfpack_di_wsolve       n               5*n
+       umfpack_dl_wsolve       n               5*n
+       umfpack_zi_wsolve       4*n             10*n
+       umfpack_zl_wsolve       4*n             10*n
+*/
diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/Contents.m b/deal.II/contrib/umfpack/UMFPACK/MATLAB/Contents.m
new file mode 100644 (file)
index 0000000..c6657b2
--- /dev/null
@@ -0,0 +1,22 @@
+%Contents of the UMFPACK sparse matrix toolbox:
+%
+% umfpack           computes x=A\b, x=A/b, or lu (A) for a sparse matrix A
+% umfpack_make      to compile umfpack for use in MATLAB
+% umfpack_details   details on all the options for using umfpack in MATLAB
+% umfpack_report    prints optional control settings and statistics
+% umfpack_demo      a long demo
+% umfpack_simple    a simple demo
+% 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
+% luflop           given L and U, computes # of flops required to compute them
+%
+% See also:
+% amd              symmetric minimum degree ordering
+% colamd            unsymmetric column approx minimum degree ordering
+% symamd            symmetric approx minimum degree ordering, based on colamd
+%
+% UMFPACK Version 4.3 (Jan. 16, 2004),  Copyright (c) 2004 by Timothy A.
+% Davis.  All Rights Reserved.  Type umfpack_details for License.
+
+help Contents
diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/GNUmakefile b/deal.II/contrib/umfpack/UMFPACK/MATLAB/GNUmakefile
new file mode 100644 (file)
index 0000000..90edfec
--- /dev/null
@@ -0,0 +1,232 @@
+#-------------------------------------------------------------------------------
+# UMFPACK GNUmakefile for the UMFPACK MATLAB mexFunction (GNU "make" only)
+#-------------------------------------------------------------------------------
+
+# UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.
+# Davis.  All Rights Reserved.  See ../README for License.
+
+all: umfpack luflop
+
+include ../Make/Make.include
+
+MX = $(MEX) -I../Include -I../Source -I../../AMD/Include -I../../AMD/Source
+
+#-------------------------------------------------------------------------------
+# 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/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 and user-callable amd_*.[ch] files (int/long versions only):
+AMD = amd_aat amd_1 amd_2 amd_dump amd_postorder amd_post_tree amd_defaults \
+       amd_order amd_control amd_info amd_valid
+
+# non-user-callable, created from umf_ltsolve.c, umf_utsolve.c,
+# umf_triplet.c, and umf_assemble.c , with int/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/long and real/complex versions:
+UMF = $(UMF_CREATED) $(UMFCH)
+
+# user-callable umfpack_*.[ch] files (int/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_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/long and real/complex versions:
+UMFPACKW = umfpack_wsolve
+
+USER = $(UMFPACKW) $(UMFPACK)
+
+# user-callable, only one version for int/long, real/complex, *.[ch] files:
+GENERIC = umfpack_timer umfpack_tictoc
+
+#-------------------------------------------------------------------------------
+# include files:
+#-------------------------------------------------------------------------------
+
+AMDH = ../../AMD/Source/amd_internal.h ../../AMD/Include/amd.h
+
+INC1 = umf_config.h umf_version.h umf_internal.h umf_triplet.h
+
+INC = ../Include/umfpack.h \
+       $(addprefix ../Source/, $(INC1)) \
+       $(addprefix ../Source/, $(addsuffix .h,$(UMFCH))) \
+       $(addprefix ../Source/, $(addsuffix .h,$(UMFINT))) \
+       $(addprefix ../Include/, $(addsuffix .h,$(USER))) \
+       $(addprefix ../Include/, $(addsuffix .h,$(GENERIC))) \
+       $(AMDH)
+
+#-------------------------------------------------------------------------------
+# Create the umfpack and amd mexFunctions for MATLAB (int versions only)
+#-------------------------------------------------------------------------------
+
+MEXI   = $(addsuffix .o, $(subst umf_,umf_m_,$(UMFINT)))
+MEXDI  = $(addsuffix .o, $(subst umf_,umf_md_,$(UMF)) $(subst umfpack_,umfpack_md_,$(USER)))
+MEXZI  = $(addsuffix .o, $(subst umf_,umf_mz_,$(UMF)) $(subst umfpack_,umfpack_mz_,$(USER)) )
+MEXAMD = $(addsuffix .o, $(subst amd_,amd_m_,$(AMD)))
+MEXGN  = $(addsuffix .o, $(subst umfpack_,umfpack_m_,$(GENERIC)))
+
+MEXUMFPACK = $(MEXI) $(MEXDI) $(MEXZI) $(MEXGN)
+
+# Note that mex has no "-o" option, thus the need for $(MV) commands.
+# If it did, then the rules would be much simpler:
+#      $(MX) -DDINT -c $< -o $@
+
+#----------------------------------------
+# integer-only routines (no real/complex):
+#----------------------------------------
+
+amd_m_%.o: ../../AMD/Source/amd_%.c $(AMDH)
+       $(MX) -DDINT -c $<
+       - $(MV) amd_$*.o $@
+
+umf_m_%.o: ../Source/umf_%.c $(INC)
+       $(MX) -DDINT -c $<
+       - $(MV) umf_$*.o $@
+
+#----------------------------------------
+# Double precision, int version, for MATLAB
+#----------------------------------------
+
+umf_md_%.o: ../Source/umf_%.c $(INC)
+       $(MX) -DDINT -c $<
+       - $(MV) umf_$*.o $@
+
+umf_md_%hsolve.o: ../Source/umf_%tsolve.c $(INC)
+       $(MX) -DDINT -DCONJUGATE_SOLVE -c $<
+       - $(MV) umf_$*tsolve.o $@
+
+umf_md_triplet_map_x.o: ../Source/umf_triplet.c $(INC)
+       $(MX) -DDINT -DDO_MAP -DDO_VALUES -c $<
+       - $(MV) umf_triplet.o $@
+
+umf_md_triplet_map_nox.o: ../Source/umf_triplet.c $(INC)
+       $(MX) -DDINT -DDO_MAP -c $<
+       - $(MV) umf_triplet.o $@
+
+umf_md_triplet_nomap_x.o: ../Source/umf_triplet.c $(INC)
+       $(MX) -DDINT -DDO_VALUES -c $<
+       - $(MV) umf_triplet.o $@
+
+umf_md_triplet_nomap_nox.o: ../Source/umf_triplet.c $(INC)
+       $(MX) -DDINT -c $<
+       - $(MV) umf_triplet.o $@
+
+umf_md_assemble_fixq.o: ../Source/umf_assemble.c $(INC)
+       $(MX) -DDINT -DFIXQ -c $<
+       - $(MV) umf_assemble.o $@
+
+umf_md_store_lu_drop.o: ../Source/umf_store_lu.c $(INC)
+       $(MX) -DDINT -DDROP -c $<
+       - $(MV) umf_store_lu.o $@
+
+umfpack_md_wsolve.o: ../Source/umfpack_solve.c $(INC)
+       $(MX) -DDINT -DWSOLVE -c $<
+       - $(MV) umfpack_solve.o $@
+
+umfpack_md_%.o: ../Source/umfpack_%.c $(INC)
+       $(MX) -DDINT -c $<
+       - $(MV) umfpack_$*.o $@
+
+#----------------------------------------
+# Complex double precision, int version, for MATLAB
+#----------------------------------------
+
+umf_mz_%.o: ../Source/umf_%.c $(INC)
+       $(MX) -DZINT -c $<
+       - $(MV) umf_$*.o $@
+
+umf_mz_%hsolve.o: ../Source/umf_%tsolve.c $(INC)
+       $(MX) -DZINT -DCONJUGATE_SOLVE -c $<
+       - $(MV) umf_$*tsolve.o $@
+
+umf_mz_triplet_map_x.o: ../Source/umf_triplet.c $(INC)
+       $(MX) -DZINT -DDO_MAP -DDO_VALUES -c $<
+       - $(MV) umf_triplet.o $@
+
+umf_mz_triplet_map_nox.o: ../Source/umf_triplet.c $(INC)
+       $(MX) -DZINT -DDO_MAP -c $<
+       - $(MV) umf_triplet.o $@
+
+umf_mz_triplet_nomap_x.o: ../Source/umf_triplet.c $(INC)
+       $(MX) -DZINT -DDO_VALUES -c $<
+       - $(MV) umf_triplet.o $@
+
+umf_mz_triplet_nomap_nox.o: ../Source/umf_triplet.c $(INC)
+       $(MX) -DZINT -c $<
+       - $(MV) umf_triplet.o $@
+
+umf_mz_assemble_fixq.o: ../Source/umf_assemble.c $(INC)
+       $(MX) -DZINT -DFIXQ -c $<
+       - $(MV) umf_assemble.o $@
+
+umf_mz_store_lu_drop.o: ../Source/umf_store_lu.c $(INC)
+       $(MX) -DZINT -DDROP -c $<
+       - $(MV) umf_store_lu.o $@
+
+umfpack_mz_wsolve.o: ../Source/umfpack_solve.c $(INC)
+       $(MX) -DZINT -DWSOLVE -c $<
+       - $(MV) umfpack_solve.o $@
+
+umfpack_mz_%.o: ../Source/umfpack_%.c $(INC)
+       $(MX) -DZINT -c $<
+       - $(MV) umfpack_$*.o $@
+
+#----------------------------------------
+# Generic routines for MATLAB
+#----------------------------------------
+
+umfpack_m_timer.o: ../Source/umfpack_timer.c $(INC)
+       $(MX) -c $<
+       - $(MV) umfpack_timer.o $@
+
+umfpack_m_tictoc.o: ../Source/umfpack_tictoc.c $(INC)
+       $(MX) -c $<
+       - $(MV) umfpack_tictoc.o $@
+
+#----------------------------------------
+# umfpack mexFunction
+#----------------------------------------
+
+umfpack: umfpackmex.c $(MEXUMFPACK) $(MEXAMD)
+       $(MX) -output umfpack umfpackmex.c $(MEXUMFPACK) $(MEXAMD)
+
+luflop: luflopmex.c
+       $(MX) -output luflop luflopmex.c
+
+#-------------------------------------------------------------------------------
+# Remove all but the files in the original distribution
+#-------------------------------------------------------------------------------
+
+purge: clean
+       - $(RM) *.mex* *.dll
diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/Makefile b/deal.II/contrib/umfpack/UMFPACK/MATLAB/Makefile
new file mode 100644 (file)
index 0000000..4501ba3
--- /dev/null
@@ -0,0 +1,436 @@
+#-------------------------------------------------------------------------------
+# UMFPACK Makefile for the UMFPACK MATLAB mexFunction (old "make" only)
+#-------------------------------------------------------------------------------
+
+# UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.
+# Davis.  All Rights Reserved.  See ../README for License.
+
+# 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.  It was created
+# automatically, via make -n using the GNUmakefile.  That way, I don't have
+# maintain two Makefiles.
+
+all: umfpack luflop
+
+include ../Make/Make.include
+
+MX = $(MEX) -I../Include -I../Source -I../../AMD/Include -I../../AMD/Source
+
+umfpack:
+       $(MX) -DDINT -c ../Source/umf_analyze.c
+       $(MV) -f umf_analyze.o umf_m_analyze.o
+       $(MX) -DDINT -c ../Source/umf_apply_order.c
+       $(MV) -f umf_apply_order.o umf_m_apply_order.o
+       $(MX) -DDINT -c ../Source/umf_colamd.c
+       $(MV) -f umf_colamd.o umf_m_colamd.o
+       $(MX) -DDINT -c ../Source/umf_free.c
+       $(MV) -f umf_free.o umf_m_free.o
+       $(MX) -DDINT -c ../Source/umf_fsize.c
+       $(MV) -f umf_fsize.o umf_m_fsize.o
+       $(MX) -DDINT -c ../Source/umf_is_permutation.c
+       $(MV) -f umf_is_permutation.o umf_m_is_permutation.o
+       $(MX) -DDINT -c ../Source/umf_malloc.c
+       $(MV) -f umf_malloc.o umf_m_malloc.o
+       $(MX) -DDINT -c ../Source/umf_realloc.c
+       $(MV) -f umf_realloc.o umf_m_realloc.o
+       $(MX) -DDINT -c ../Source/umf_report_perm.c
+       $(MV) -f umf_report_perm.o umf_m_report_perm.o
+       $(MX) -DDINT -c ../Source/umf_singletons.c
+       $(MV) -f umf_singletons.o umf_m_singletons.o
+       $(MX) -DDINT -DCONJUGATE_SOLVE -c ../Source/umf_ltsolve.c
+       $(MV) -f umf_ltsolve.o umf_md_lhsolve.o
+       $(MX) -DDINT -DCONJUGATE_SOLVE -c ../Source/umf_utsolve.c
+       $(MV) -f umf_utsolve.o umf_md_uhsolve.o
+       $(MX) -DDINT -DDO_MAP -c ../Source/umf_triplet.c
+       $(MV) -f umf_triplet.o umf_md_triplet_map_nox.o
+       $(MX) -DDINT -DDO_VALUES -c ../Source/umf_triplet.c
+       $(MV) -f umf_triplet.o umf_md_triplet_nomap_x.o
+       $(MX) -DDINT -c ../Source/umf_triplet.c
+       $(MV) -f umf_triplet.o umf_md_triplet_nomap_nox.o
+       $(MX) -DDINT -DDO_MAP -DDO_VALUES -c ../Source/umf_triplet.c
+       $(MV) -f umf_triplet.o umf_md_triplet_map_x.o
+       $(MX) -DDINT -DFIXQ -c ../Source/umf_assemble.c
+       $(MV) -f umf_assemble.o umf_md_assemble_fixq.o
+       $(MX) -DDINT -DDROP -c ../Source/umf_store_lu.c
+       $(MV) -f umf_store_lu.o umf_md_store_lu_drop.o
+       $(MX) -DDINT -c ../Source/umf_assemble.c
+       $(MV) -f umf_assemble.o umf_md_assemble.o
+       $(MX) -DDINT -c ../Source/umf_blas3_update.c
+       $(MV) -f umf_blas3_update.o umf_md_blas3_update.o
+       $(MX) -DDINT -c ../Source/umf_build_tuples.c
+       $(MV) -f umf_build_tuples.o umf_md_build_tuples.o
+       $(MX) -DDINT -c ../Source/umf_create_element.c
+       $(MV) -f umf_create_element.o umf_md_create_element.o
+       $(MX) -DDINT -c ../Source/umf_dump.c
+       $(MV) -f umf_dump.o umf_md_dump.o
+       $(MX) -DDINT -c ../Source/umf_extend_front.c
+       $(MV) -f umf_extend_front.o umf_md_extend_front.o
+       $(MX) -DDINT -c ../Source/umf_garbage_collection.c
+       $(MV) -f umf_garbage_collection.o umf_md_garbage_collection.o
+       $(MX) -DDINT -c ../Source/umf_get_memory.c
+       $(MV) -f umf_get_memory.o umf_md_get_memory.o
+       $(MX) -DDINT -c ../Source/umf_init_front.c
+       $(MV) -f umf_init_front.o umf_md_init_front.o
+       $(MX) -DDINT -c ../Source/umf_kernel.c
+       $(MV) -f umf_kernel.o umf_md_kernel.o
+       $(MX) -DDINT -c ../Source/umf_kernel_init.c
+       $(MV) -f umf_kernel_init.o umf_md_kernel_init.o
+       $(MX) -DDINT -c ../Source/umf_kernel_wrapup.c
+       $(MV) -f umf_kernel_wrapup.o umf_md_kernel_wrapup.o
+       $(MX) -DDINT -c ../Source/umf_local_search.c
+       $(MV) -f umf_local_search.o umf_md_local_search.o
+       $(MX) -DDINT -c ../Source/umf_lsolve.c
+       $(MV) -f umf_lsolve.o umf_md_lsolve.o
+       $(MX) -DDINT -c ../Source/umf_ltsolve.c
+       $(MV) -f umf_ltsolve.o umf_md_ltsolve.o
+       $(MX) -DDINT -c ../Source/umf_mem_alloc_element.c
+       $(MV) -f umf_mem_alloc_element.o umf_md_mem_alloc_element.o
+       $(MX) -DDINT -c ../Source/umf_mem_alloc_head_block.c
+       $(MV) -f umf_mem_alloc_head_block.o umf_md_mem_alloc_head_block.o
+       $(MX) -DDINT -c ../Source/umf_mem_alloc_tail_block.c
+       $(MV) -f umf_mem_alloc_tail_block.o umf_md_mem_alloc_tail_block.o
+       $(MX) -DDINT -c ../Source/umf_mem_free_tail_block.c
+       $(MV) -f umf_mem_free_tail_block.o umf_md_mem_free_tail_block.o
+       $(MX) -DDINT -c ../Source/umf_mem_init_memoryspace.c
+       $(MV) -f umf_mem_init_memoryspace.o umf_md_mem_init_memoryspace.o
+       $(MX) -DDINT -c ../Source/umf_report_vector.c
+       $(MV) -f umf_report_vector.o umf_md_report_vector.o
+       $(MX) -DDINT -c ../Source/umf_row_search.c
+       $(MV) -f umf_row_search.o umf_md_row_search.o
+       $(MX) -DDINT -c ../Source/umf_scale_column.c
+       $(MV) -f umf_scale_column.o umf_md_scale_column.o
+       $(MX) -DDINT -c ../Source/umf_set_stats.c
+       $(MV) -f umf_set_stats.o umf_md_set_stats.o
+       $(MX) -DDINT -c ../Source/umf_solve.c
+       $(MV) -f umf_solve.o umf_md_solve.o
+       $(MX) -DDINT -c ../Source/umf_symbolic_usage.c
+       $(MV) -f umf_symbolic_usage.o umf_md_symbolic_usage.o
+       $(MX) -DDINT -c ../Source/umf_transpose.c
+       $(MV) -f umf_transpose.o umf_md_transpose.o
+       $(MX) -DDINT -c ../Source/umf_tuple_lengths.c
+       $(MV) -f umf_tuple_lengths.o umf_md_tuple_lengths.o
+       $(MX) -DDINT -c ../Source/umf_usolve.c
+       $(MV) -f umf_usolve.o umf_md_usolve.o
+       $(MX) -DDINT -c ../Source/umf_utsolve.c
+       $(MV) -f umf_utsolve.o umf_md_utsolve.o
+       $(MX) -DDINT -c ../Source/umf_valid_numeric.c
+       $(MV) -f umf_valid_numeric.o umf_md_valid_numeric.o
+       $(MX) -DDINT -c ../Source/umf_valid_symbolic.c
+       $(MV) -f umf_valid_symbolic.o umf_md_valid_symbolic.o
+       $(MX) -DDINT -c ../Source/umf_grow_front.c
+       $(MV) -f umf_grow_front.o umf_md_grow_front.o
+       $(MX) -DDINT -c ../Source/umf_start_front.c
+       $(MV) -f umf_start_front.o umf_md_start_front.o
+       $(MX) -DDINT -c ../Source/umf_2by2.c
+       $(MV) -f umf_2by2.o umf_md_2by2.o
+       $(MX) -DDINT -c ../Source/umf_store_lu.c
+       $(MV) -f umf_store_lu.o umf_md_store_lu.o
+       $(MX) -DDINT -c ../Source/umf_scale.c
+       $(MV) -f umf_scale.o umf_md_scale.o
+       $(MX) -DDINT -DWSOLVE -c ../Source/umfpack_solve.c
+       $(MV) -f umfpack_solve.o umfpack_md_wsolve.o
+       $(MX) -DDINT -c ../Source/umfpack_col_to_triplet.c
+       $(MV) -f umfpack_col_to_triplet.o umfpack_md_col_to_triplet.o
+       $(MX) -DDINT -c ../Source/umfpack_defaults.c
+       $(MV) -f umfpack_defaults.o umfpack_md_defaults.o
+       $(MX) -DDINT -c ../Source/umfpack_free_numeric.c
+       $(MV) -f umfpack_free_numeric.o umfpack_md_free_numeric.o
+       $(MX) -DDINT -c ../Source/umfpack_free_symbolic.c
+       $(MV) -f umfpack_free_symbolic.o umfpack_md_free_symbolic.o
+       $(MX) -DDINT -c ../Source/umfpack_get_numeric.c
+       $(MV) -f umfpack_get_numeric.o umfpack_md_get_numeric.o
+       $(MX) -DDINT -c ../Source/umfpack_get_lunz.c
+       $(MV) -f umfpack_get_lunz.o umfpack_md_get_lunz.o
+       $(MX) -DDINT -c ../Source/umfpack_get_symbolic.c
+       $(MV) -f umfpack_get_symbolic.o umfpack_md_get_symbolic.o
+       $(MX) -DDINT -c ../Source/umfpack_numeric.c
+       $(MV) -f umfpack_numeric.o umfpack_md_numeric.o
+       $(MX) -DDINT -c ../Source/umfpack_qsymbolic.c
+       $(MV) -f umfpack_qsymbolic.o umfpack_md_qsymbolic.o
+       $(MX) -DDINT -c ../Source/umfpack_report_control.c
+       $(MV) -f umfpack_report_control.o umfpack_md_report_control.o
+       $(MX) -DDINT -c ../Source/umfpack_report_info.c
+       $(MV) -f umfpack_report_info.o umfpack_md_report_info.o
+       $(MX) -DDINT -c ../Source/umfpack_report_matrix.c
+       $(MV) -f umfpack_report_matrix.o umfpack_md_report_matrix.o
+       $(MX) -DDINT -c ../Source/umfpack_report_numeric.c
+       $(MV) -f umfpack_report_numeric.o umfpack_md_report_numeric.o
+       $(MX) -DDINT -c ../Source/umfpack_report_perm.c
+       $(MV) -f umfpack_report_perm.o umfpack_md_report_perm.o
+       $(MX) -DDINT -c ../Source/umfpack_report_status.c
+       $(MV) -f umfpack_report_status.o umfpack_md_report_status.o
+       $(MX) -DDINT -c ../Source/umfpack_report_symbolic.c
+       $(MV) -f umfpack_report_symbolic.o umfpack_md_report_symbolic.o
+       $(MX) -DDINT -c ../Source/umfpack_report_triplet.c
+       $(MV) -f umfpack_report_triplet.o umfpack_md_report_triplet.o
+       $(MX) -DDINT -c ../Source/umfpack_report_vector.c
+       $(MV) -f umfpack_report_vector.o umfpack_md_report_vector.o
+       $(MX) -DDINT -c ../Source/umfpack_solve.c
+       $(MV) -f umfpack_solve.o umfpack_md_solve.o
+       $(MX) -DDINT -c ../Source/umfpack_symbolic.c
+       $(MV) -f umfpack_symbolic.o umfpack_md_symbolic.o
+       $(MX) -DDINT -c ../Source/umfpack_transpose.c
+       $(MV) -f umfpack_transpose.o umfpack_md_transpose.o
+       $(MX) -DDINT -c ../Source/umfpack_triplet_to_col.c
+       $(MV) -f umfpack_triplet_to_col.o umfpack_md_triplet_to_col.o
+       $(MX) -DDINT -c ../Source/umfpack_scale.c
+       $(MV) -f umfpack_scale.o umfpack_md_scale.o
+       $(MX) -DDINT -c ../Source/umfpack_load_numeric.c
+       $(MV) -f umfpack_load_numeric.o umfpack_md_load_numeric.o
+       $(MX) -DDINT -c ../Source/umfpack_save_numeric.c
+       $(MV) -f umfpack_save_numeric.o umfpack_md_save_numeric.o
+       $(MX) -DDINT -c ../Source/umfpack_load_symbolic.c
+       $(MV) -f umfpack_load_symbolic.o umfpack_md_load_symbolic.o
+       $(MX) -DDINT -c ../Source/umfpack_save_symbolic.c
+       $(MV) -f umfpack_save_symbolic.o umfpack_md_save_symbolic.o
+       $(MX) -DZINT -DCONJUGATE_SOLVE -c ../Source/umf_ltsolve.c
+       $(MV) -f umf_ltsolve.o umf_mz_lhsolve.o
+       $(MX) -DZINT -DCONJUGATE_SOLVE -c ../Source/umf_utsolve.c
+       $(MV) -f umf_utsolve.o umf_mz_uhsolve.o
+       $(MX) -DZINT -DDO_MAP -c ../Source/umf_triplet.c
+       $(MV) -f umf_triplet.o umf_mz_triplet_map_nox.o
+       $(MX) -DZINT -DDO_VALUES -c ../Source/umf_triplet.c
+       $(MV) -f umf_triplet.o umf_mz_triplet_nomap_x.o
+       $(MX) -DZINT -c ../Source/umf_triplet.c
+       $(MV) -f umf_triplet.o umf_mz_triplet_nomap_nox.o
+       $(MX) -DZINT -DDO_MAP -DDO_VALUES -c ../Source/umf_triplet.c
+       $(MV) -f umf_triplet.o umf_mz_triplet_map_x.o
+       $(MX) -DZINT -DFIXQ -c ../Source/umf_assemble.c
+       $(MV) -f umf_assemble.o umf_mz_assemble_fixq.o
+       $(MX) -DZINT -DDROP -c ../Source/umf_store_lu.c
+       $(MV) -f umf_store_lu.o umf_mz_store_lu_drop.o
+       $(MX) -DZINT -c ../Source/umf_assemble.c
+       $(MV) -f umf_assemble.o umf_mz_assemble.o
+       $(MX) -DZINT -c ../Source/umf_blas3_update.c
+       $(MV) -f umf_blas3_update.o umf_mz_blas3_update.o
+       $(MX) -DZINT -c ../Source/umf_build_tuples.c
+       $(MV) -f umf_build_tuples.o umf_mz_build_tuples.o
+       $(MX) -DZINT -c ../Source/umf_create_element.c
+       $(MV) -f umf_create_element.o umf_mz_create_element.o
+       $(MX) -DZINT -c ../Source/umf_dump.c
+       $(MV) -f umf_dump.o umf_mz_dump.o
+       $(MX) -DZINT -c ../Source/umf_extend_front.c
+       $(MV) -f umf_extend_front.o umf_mz_extend_front.o
+       $(MX) -DZINT -c ../Source/umf_garbage_collection.c
+       $(MV) -f umf_garbage_collection.o umf_mz_garbage_collection.o
+       $(MX) -DZINT -c ../Source/umf_get_memory.c
+       $(MV) -f umf_get_memory.o umf_mz_get_memory.o
+       $(MX) -DZINT -c ../Source/umf_init_front.c
+       $(MV) -f umf_init_front.o umf_mz_init_front.o
+       $(MX) -DZINT -c ../Source/umf_kernel.c
+       $(MV) -f umf_kernel.o umf_mz_kernel.o
+       $(MX) -DZINT -c ../Source/umf_kernel_init.c
+       $(MV) -f umf_kernel_init.o umf_mz_kernel_init.o
+       $(MX) -DZINT -c ../Source/umf_kernel_wrapup.c
+       $(MV) -f umf_kernel_wrapup.o umf_mz_kernel_wrapup.o
+       $(MX) -DZINT -c ../Source/umf_local_search.c
+       $(MV) -f umf_local_search.o umf_mz_local_search.o
+       $(MX) -DZINT -c ../Source/umf_lsolve.c
+       $(MV) -f umf_lsolve.o umf_mz_lsolve.o
+       $(MX) -DZINT -c ../Source/umf_ltsolve.c
+       $(MV) -f umf_ltsolve.o umf_mz_ltsolve.o
+       $(MX) -DZINT -c ../Source/umf_mem_alloc_element.c
+       $(MV) -f umf_mem_alloc_element.o umf_mz_mem_alloc_element.o
+       $(MX) -DZINT -c ../Source/umf_mem_alloc_head_block.c
+       $(MV) -f umf_mem_alloc_head_block.o umf_mz_mem_alloc_head_block.o
+       $(MX) -DZINT -c ../Source/umf_mem_alloc_tail_block.c
+       $(MV) -f umf_mem_alloc_tail_block.o umf_mz_mem_alloc_tail_block.o
+       $(MX) -DZINT -c ../Source/umf_mem_free_tail_block.c
+       $(MV) -f umf_mem_free_tail_block.o umf_mz_mem_free_tail_block.o
+       $(MX) -DZINT -c ../Source/umf_mem_init_memoryspace.c
+       $(MV) -f umf_mem_init_memoryspace.o umf_mz_mem_init_memoryspace.o
+       $(MX) -DZINT -c ../Source/umf_report_vector.c
+       $(MV) -f umf_report_vector.o umf_mz_report_vector.o
+       $(MX) -DZINT -c ../Source/umf_row_search.c
+       $(MV) -f umf_row_search.o umf_mz_row_search.o
+       $(MX) -DZINT -c ../Source/umf_scale_column.c
+       $(MV) -f umf_scale_column.o umf_mz_scale_column.o
+       $(MX) -DZINT -c ../Source/umf_set_stats.c
+       $(MV) -f umf_set_stats.o umf_mz_set_stats.o
+       $(MX) -DZINT -c ../Source/umf_solve.c
+       $(MV) -f umf_solve.o umf_mz_solve.o
+       $(MX) -DZINT -c ../Source/umf_symbolic_usage.c
+       $(MV) -f umf_symbolic_usage.o umf_mz_symbolic_usage.o
+       $(MX) -DZINT -c ../Source/umf_transpose.c
+       $(MV) -f umf_transpose.o umf_mz_transpose.o
+       $(MX) -DZINT -c ../Source/umf_tuple_lengths.c
+       $(MV) -f umf_tuple_lengths.o umf_mz_tuple_lengths.o
+       $(MX) -DZINT -c ../Source/umf_usolve.c
+       $(MV) -f umf_usolve.o umf_mz_usolve.o
+       $(MX) -DZINT -c ../Source/umf_utsolve.c
+       $(MV) -f umf_utsolve.o umf_mz_utsolve.o
+       $(MX) -DZINT -c ../Source/umf_valid_numeric.c
+       $(MV) -f umf_valid_numeric.o umf_mz_valid_numeric.o
+       $(MX) -DZINT -c ../Source/umf_valid_symbolic.c
+       $(MV) -f umf_valid_symbolic.o umf_mz_valid_symbolic.o
+       $(MX) -DZINT -c ../Source/umf_grow_front.c
+       $(MV) -f umf_grow_front.o umf_mz_grow_front.o
+       $(MX) -DZINT -c ../Source/umf_start_front.c
+       $(MV) -f umf_start_front.o umf_mz_start_front.o
+       $(MX) -DZINT -c ../Source/umf_2by2.c
+       $(MV) -f umf_2by2.o umf_mz_2by2.o
+       $(MX) -DZINT -c ../Source/umf_store_lu.c
+       $(MV) -f umf_store_lu.o umf_mz_store_lu.o
+       $(MX) -DZINT -c ../Source/umf_scale.c
+       $(MV) -f umf_scale.o umf_mz_scale.o
+       $(MX) -DZINT -DWSOLVE -c ../Source/umfpack_solve.c
+       $(MV) -f umfpack_solve.o umfpack_mz_wsolve.o
+       $(MX) -DZINT -c ../Source/umfpack_col_to_triplet.c
+       $(MV) -f umfpack_col_to_triplet.o umfpack_mz_col_to_triplet.o
+       $(MX) -DZINT -c ../Source/umfpack_defaults.c
+       $(MV) -f umfpack_defaults.o umfpack_mz_defaults.o
+       $(MX) -DZINT -c ../Source/umfpack_free_numeric.c
+       $(MV) -f umfpack_free_numeric.o umfpack_mz_free_numeric.o
+       $(MX) -DZINT -c ../Source/umfpack_free_symbolic.c
+       $(MV) -f umfpack_free_symbolic.o umfpack_mz_free_symbolic.o
+       $(MX) -DZINT -c ../Source/umfpack_get_numeric.c
+       $(MV) -f umfpack_get_numeric.o umfpack_mz_get_numeric.o
+       $(MX) -DZINT -c ../Source/umfpack_get_lunz.c
+       $(MV) -f umfpack_get_lunz.o umfpack_mz_get_lunz.o
+       $(MX) -DZINT -c ../Source/umfpack_get_symbolic.c
+       $(MV) -f umfpack_get_symbolic.o umfpack_mz_get_symbolic.o
+       $(MX) -DZINT -c ../Source/umfpack_numeric.c
+       $(MV) -f umfpack_numeric.o umfpack_mz_numeric.o
+       $(MX) -DZINT -c ../Source/umfpack_qsymbolic.c
+       $(MV) -f umfpack_qsymbolic.o umfpack_mz_qsymbolic.o
+       $(MX) -DZINT -c ../Source/umfpack_report_control.c
+       $(MV) -f umfpack_report_control.o umfpack_mz_report_control.o
+       $(MX) -DZINT -c ../Source/umfpack_report_info.c
+       $(MV) -f umfpack_report_info.o umfpack_mz_report_info.o
+       $(MX) -DZINT -c ../Source/umfpack_report_matrix.c
+       $(MV) -f umfpack_report_matrix.o umfpack_mz_report_matrix.o
+       $(MX) -DZINT -c ../Source/umfpack_report_numeric.c
+       $(MV) -f umfpack_report_numeric.o umfpack_mz_report_numeric.o
+       $(MX) -DZINT -c ../Source/umfpack_report_perm.c
+       $(MV) -f umfpack_report_perm.o umfpack_mz_report_perm.o
+       $(MX) -DZINT -c ../Source/umfpack_report_status.c
+       $(MV) -f umfpack_report_status.o umfpack_mz_report_status.o
+       $(MX) -DZINT -c ../Source/umfpack_report_symbolic.c
+       $(MV) -f umfpack_report_symbolic.o umfpack_mz_report_symbolic.o
+       $(MX) -DZINT -c ../Source/umfpack_report_triplet.c
+       $(MV) -f umfpack_report_triplet.o umfpack_mz_report_triplet.o
+       $(MX) -DZINT -c ../Source/umfpack_report_vector.c
+       $(MV) -f umfpack_report_vector.o umfpack_mz_report_vector.o
+       $(MX) -DZINT -c ../Source/umfpack_solve.c
+       $(MV) -f umfpack_solve.o umfpack_mz_solve.o
+       $(MX) -DZINT -c ../Source/umfpack_symbolic.c
+       $(MV) -f umfpack_symbolic.o umfpack_mz_symbolic.o
+       $(MX) -DZINT -c ../Source/umfpack_transpose.c
+       $(MV) -f umfpack_transpose.o umfpack_mz_transpose.o
+       $(MX) -DZINT -c ../Source/umfpack_triplet_to_col.c
+       $(MV) -f umfpack_triplet_to_col.o umfpack_mz_triplet_to_col.o
+       $(MX) -DZINT -c ../Source/umfpack_scale.c
+       $(MV) -f umfpack_scale.o umfpack_mz_scale.o
+       $(MX) -DZINT -c ../Source/umfpack_load_numeric.c
+       $(MV) -f umfpack_load_numeric.o umfpack_mz_load_numeric.o
+       $(MX) -DZINT -c ../Source/umfpack_save_numeric.c
+       $(MV) -f umfpack_save_numeric.o umfpack_mz_save_numeric.o
+       $(MX) -DZINT -c ../Source/umfpack_load_symbolic.c
+       $(MV) -f umfpack_load_symbolic.o umfpack_mz_load_symbolic.o
+       $(MX) -DZINT -c ../Source/umfpack_save_symbolic.c
+       $(MV) -f umfpack_save_symbolic.o umfpack_mz_save_symbolic.o
+       $(MX) -c ../Source/umfpack_timer.c
+       $(MV) -f umfpack_timer.o umfpack_m_timer.o
+       $(MX) -c ../Source/umfpack_tictoc.c
+       $(MV) -f umfpack_tictoc.o umfpack_m_tictoc.o
+       $(MX) -DDINT -c ../../AMD/Source/amd_aat.c
+       $(MV) -f amd_aat.o amd_m_aat.o
+       $(MX) -DDINT -c ../../AMD/Source/amd_1.c
+       $(MV) -f amd_1.o amd_m_1.o
+       $(MX) -DDINT -c ../../AMD/Source/amd_2.c
+       $(MV) -f amd_2.o amd_m_2.o
+       $(MX) -DDINT -c ../../AMD/Source/amd_dump.c
+       $(MV) -f amd_dump.o amd_m_dump.o
+       $(MX) -DDINT -c ../../AMD/Source/amd_postorder.c
+       $(MV) -f amd_postorder.o amd_m_postorder.o
+       $(MX) -DDINT -c ../../AMD/Source/amd_post_tree.c
+       $(MV) -f amd_post_tree.o amd_m_post_tree.o
+       $(MX) -DDINT -c ../../AMD/Source/amd_defaults.c
+       $(MV) -f amd_defaults.o amd_m_defaults.o
+       $(MX) -DDINT -c ../../AMD/Source/amd_order.c
+       $(MV) -f amd_order.o amd_m_order.o
+       $(MX) -DDINT -c ../../AMD/Source/amd_control.c
+       $(MV) -f amd_control.o amd_m_control.o
+       $(MX) -DDINT -c ../../AMD/Source/amd_info.c
+       $(MV) -f amd_info.o amd_m_info.o
+       $(MX) -DDINT -c ../../AMD/Source/amd_valid.c
+       $(MV) -f amd_valid.o amd_m_valid.o
+       $(MX) -output umfpack umfpackmex.c \
+           umf_m_analyze.o umf_m_apply_order.o umf_m_colamd.o umf_m_free.o \
+           umf_m_fsize.o umf_m_is_permutation.o umf_m_malloc.o \
+           umf_m_realloc.o umf_m_report_perm.o umf_m_singletons.o \
+           umf_md_lhsolve.o umf_md_uhsolve.o umf_md_triplet_map_nox.o \
+           umf_md_triplet_nomap_x.o umf_md_triplet_nomap_nox.o \
+           umf_md_triplet_map_x.o umf_md_assemble_fixq.o \
+           umf_md_store_lu_drop.o umf_md_assemble.o umf_md_blas3_update.o \
+           umf_md_build_tuples.o umf_md_create_element.o umf_md_dump.o \
+           umf_md_extend_front.o umf_md_garbage_collection.o \
+           umf_md_get_memory.o umf_md_init_front.o umf_md_kernel.o \
+           umf_md_kernel_init.o umf_md_kernel_wrapup.o umf_md_local_search.o \
+           umf_md_lsolve.o umf_md_ltsolve.o umf_md_mem_alloc_element.o \
+           umf_md_mem_alloc_head_block.o umf_md_mem_alloc_tail_block.o \
+           umf_md_mem_free_tail_block.o umf_md_mem_init_memoryspace.o \
+           umf_md_report_vector.o umf_md_row_search.o umf_md_scale_column.o \
+           umf_md_set_stats.o umf_md_solve.o umf_md_symbolic_usage.o \
+           umf_md_transpose.o umf_md_tuple_lengths.o umf_md_usolve.o \
+           umf_md_utsolve.o umf_md_valid_numeric.o umf_md_valid_symbolic.o \
+           umf_md_grow_front.o umf_md_start_front.o umf_md_2by2.o \
+           umf_md_store_lu.o umf_md_scale.o umfpack_md_wsolve.o \
+           umfpack_md_col_to_triplet.o umfpack_md_defaults.o \
+           umfpack_md_free_numeric.o umfpack_md_free_symbolic.o \
+           umfpack_md_get_numeric.o umfpack_md_get_lunz.o \
+           umfpack_md_get_symbolic.o umfpack_md_numeric.o \
+           umfpack_md_qsymbolic.o umfpack_md_report_control.o \
+           umfpack_md_report_info.o umfpack_md_report_matrix.o \
+           umfpack_md_report_numeric.o umfpack_md_report_perm.o \
+           umfpack_md_report_status.o umfpack_md_report_symbolic.o \
+           umfpack_md_report_triplet.o umfpack_md_report_vector.o \
+           umfpack_md_solve.o umfpack_md_symbolic.o umfpack_md_transpose.o \
+           umfpack_md_triplet_to_col.o umfpack_md_scale.o \
+           umfpack_md_load_numeric.o umfpack_md_save_numeric.o \
+           umfpack_md_load_symbolic.o umfpack_md_save_symbolic.o \
+           umf_mz_lhsolve.o umf_mz_uhsolve.o umf_mz_triplet_map_nox.o \
+           umf_mz_triplet_nomap_x.o umf_mz_triplet_nomap_nox.o \
+           umf_mz_triplet_map_x.o umf_mz_assemble_fixq.o \
+           umf_mz_store_lu_drop.o umf_mz_assemble.o umf_mz_blas3_update.o \
+           umf_mz_build_tuples.o umf_mz_create_element.o umf_mz_dump.o \
+           umf_mz_extend_front.o umf_mz_garbage_collection.o \
+           umf_mz_get_memory.o umf_mz_init_front.o umf_mz_kernel.o \
+           umf_mz_kernel_init.o umf_mz_kernel_wrapup.o umf_mz_local_search.o \
+           umf_mz_lsolve.o umf_mz_ltsolve.o umf_mz_mem_alloc_element.o \
+           umf_mz_mem_alloc_head_block.o umf_mz_mem_alloc_tail_block.o \
+           umf_mz_mem_free_tail_block.o umf_mz_mem_init_memoryspace.o \
+           umf_mz_report_vector.o umf_mz_row_search.o umf_mz_scale_column.o \
+           umf_mz_set_stats.o umf_mz_solve.o umf_mz_symbolic_usage.o \
+           umf_mz_transpose.o umf_mz_tuple_lengths.o umf_mz_usolve.o \
+           umf_mz_utsolve.o umf_mz_valid_numeric.o umf_mz_valid_symbolic.o \
+           umf_mz_grow_front.o umf_mz_start_front.o umf_mz_2by2.o \
+           umf_mz_store_lu.o umf_mz_scale.o umfpack_mz_wsolve.o \
+           umfpack_mz_col_to_triplet.o umfpack_mz_defaults.o \
+           umfpack_mz_free_numeric.o umfpack_mz_free_symbolic.o \
+           umfpack_mz_get_numeric.o umfpack_mz_get_lunz.o \
+           umfpack_mz_get_symbolic.o umfpack_mz_numeric.o \
+           umfpack_mz_qsymbolic.o umfpack_mz_report_control.o \
+           umfpack_mz_report_info.o umfpack_mz_report_matrix.o \
+           umfpack_mz_report_numeric.o umfpack_mz_report_perm.o \
+           umfpack_mz_report_status.o umfpack_mz_report_symbolic.o \
+           umfpack_mz_report_triplet.o umfpack_mz_report_vector.o \
+           umfpack_mz_solve.o umfpack_mz_symbolic.o umfpack_mz_transpose.o \
+           umfpack_mz_triplet_to_col.o umfpack_mz_scale.o \
+           umfpack_mz_load_numeric.o umfpack_mz_save_numeric.o \
+           umfpack_mz_load_symbolic.o umfpack_mz_save_symbolic.o \
+           umfpack_m_timer.o umfpack_m_tictoc.o \
+           amd_m_aat.o amd_m_1.o amd_m_2.o amd_m_dump.o \
+           amd_m_postorder.o amd_m_post_tree.o amd_m_defaults.o amd_m_order.o \
+           amd_m_control.o amd_m_info.o amd_m_valid.o
+
+luflop: luflopmex.c
+       $(MX) -output luflop luflopmex.c
+
+#-------------------------------------------------------------------------------
+# Remove all but the files in the original distribution
+#-------------------------------------------------------------------------------
+
+purge: clean
+       - $(RM) *.mex* *.dll
diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/lu_normest.m b/deal.II/contrib/umfpack/UMFPACK/MATLAB/lu_normest.m
new file mode 100644 (file)
index 0000000..ea3490c
--- /dev/null
@@ -0,0 +1,106 @@
+function rho = lu_normest (A, L, U)
+% LU_NORMEST:  estimate the 1-norm of A-L*U without computing L*U
+%
+% Usage:
+%
+%       rho = lu_normest (A, L, U)
+%
+% which estimates the computation of the 1-norm:
+%
+%       rho = norm (A-L*U, 1) 
+%
+% Authors:  William W. Hager, Math Dept., Univ. of Florida
+%       Timothy A. Davis, CISE Dept., Univ. of Florida
+%       Gainesville, FL, 32611, USA.
+%       based on normest1, contributed on November, 1997
+%
+% This code can be quite easily adapted to estimate the 1-norm of any 
+% matrix E, where E itself is dense or not explicitly represented, but the
+% computation of E (and E') times a vector is easy.  In this case, our matrix
+% of interest is:
+%
+%       E = A-L*U
+%
+% That is, L*U is the LU factorization of A, where A, L and U
+% are sparse.  This code works for dense matrices A and L too,
+% but it would not be needed in that case, since E is easy to compute
+% explicitly.  For sparse A, L, and U, computing E explicitly would be quite
+% expensive, and thus normest (A-L*U) would be prohibitive.
+%
+% For a detailed description, see Davis, T. A. and Hager, W. W.,
+% Modifying a sparse Cholesky factorization, SIAM J. Matrix Analysis and
+% Applications, 1999, vol. 20, no. 3, 606-627.
+
+% The three places that the matrix-vector multiply E*x is used are highlighted.
+% Note that E is never formed explicity.
+
+[m n] = size (A) ;
+
+if (m ~= n)
+    % pad A, L, and U with zeros so that they are all square
+    if (m < n)
+        U = [ U ; (sparse (n-m,n)) ] ;
+        L = [ L , (sparse (m,n-m)) ; (sparse (n-m,n)) ] ;
+        A = [ A ; (sparse (n-m,n)) ] ;
+    else
+        U = [ U , (sparse (n,m-n)) ; (sparse (m-n,m)) ] ;
+        L = [ L , (sparse (m,m-n)) ] ;
+        A = [ A , (sparse (m,m-n)) ] ;
+    end
+end
+
+[m n] = size (A) ;
+
+notvisited = ones (m, 1) ;  % nonvisited(j) is zero if j is visited, 1 otherwise
+rho = 0 ;    % the global rho
+
+At = A' ;
+Lt = L' ;
+
+for trial = 1:3 % {
+
+   x = notvisited ./ sum (notvisited) ;
+   rho1 = 0 ;    % the current rho for this trial
+
+   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+   %%% COMPUTE Ex1 = E*x EFFICIENTLY: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+   Ex1 = (A*x) - L*(U*x) ;
+   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+   rho2 = norm (Ex1, 1) ;
+
+   while rho2 > rho1 % {
+
+        rho1 = rho2 ;
+        y = 2*(Ex1 >= 0) - 1 ;
+
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        %%% COMPUTE z = E'*y EFFICIENTLY: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        z = (A'*y) - U'*(L'*y) ;
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+        [zj, j] = max (abs (z .* notvisited)) ;
+        j = j (1) ;
+        if (abs (z (j)) > z'*x) % {
+            x = zeros (m, 1) ;
+            x (j) = 1 ;
+            notvisited (j) = 0 ;
+        else % } {
+            break ;
+        end % }
+
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        %%% COMPUTE Ex1 = E*x EFFICIENTLY: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        Ex1 = (A*x) - L*(U*x) ;
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+        rho2 = norm (Ex1, 1) ;
+
+    end % }
+
+    rho = max (rho, rho1) ;
+
+end % }
diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/luflop.m b/deal.II/contrib/umfpack/UMFPACK/MATLAB/luflop.m
new file mode 100644 (file)
index 0000000..dcc080b
--- /dev/null
@@ -0,0 +1,24 @@
+function f = luflop (L, U)
+%LUFLOP
+%
+% f = luflop (L, U)
+%
+% Given an LU factorization, compute how many flops took to compute it.  This
+% is the same as (assuming U has a zero-free diagonal):
+%
+%   Lnz = full (sum (spones (L))) - 1 ;
+%   Unz = full (sum (spones (U')))' - 1 ;
+%   f = 2*Lnz*Unz + sum (Lnz) ;
+%
+% except that no extra workspace is allocated for spones (L) and spones (U).
+% L and U must be sparse.
+%
+% Note: the above expression has a subtle undercount when exact numerical
+% cancelation occurs.  Try [L,U,P] = lu (sparse (ones (10))) and then 
+% luflop (L,U).
+
+% UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.
+% Davis.  All Rights Reserved.  Type umfpack_details for License.
+
+help luflop
+error ('luflop mexFunction not found!  Use umfpack_make to compile luflop.') ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/luflopmex.c b/deal.II/contrib/umfpack/UMFPACK/MATLAB/luflopmex.c
new file mode 100644 (file)
index 0000000..5342856
--- /dev/null
@@ -0,0 +1,121 @@
+/* ========================================================================== */
+/* === luflop  mexFunction ================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    f = luflop (L, U) ;
+
+    Given L and U, compute:
+
+        Lnz = full (sum (spones (L))) - 1 ;
+        Unz = full (sum (spones (U')))' - 1 ;
+        f = 2*Lnz*Unz + sum (Lnz) ;
+
+    without allocating O (lunz) space.
+
+*/
+
+#include "mex.h"
+#include "matrix.h"
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+void mexFunction
+(
+    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 *Lp, *Li, *Up, *Ui, *Unz, n, k, row, col, p, Lnz_k, Unz_k ;
+    mxArray *Lmatrix, *Umatrix ;
+    double flop_count, *pflop ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs L, U */
+    /* ---------------------------------------------------------------------- */
+
+    if (nrhs != 2)
+    {
+       mexErrMsgTxt ("Usage:  f = luflop (L, U)") ;
+    }
+
+    Lmatrix = (mxArray *) prhs [0] ;
+    Umatrix = (mxArray *) prhs [1] ;
+
+    n = mxGetM (Lmatrix) ;
+    if (n != mxGetN (Lmatrix) || n != mxGetM (Umatrix) || n != mxGetN (Umatrix))
+    {
+       mexErrMsgTxt ("Usage:  f = luflop (L, U) ;  L and U must be square") ;
+    }
+
+    if (!mxIsSparse (Lmatrix) || !mxIsSparse (Umatrix))
+    {
+       mexErrMsgTxt ("Usage:  f = luflop (L, U) ;  L and U must be sparse") ;
+    }
+
+    Lp = mxGetJc (Lmatrix) ;
+    Li = mxGetIr (Lmatrix) ;
+
+    Up = mxGetJc (Umatrix) ;
+    Ui = mxGetIr (Umatrix) ;
+
+    Unz = (int *) mxMalloc (n * sizeof (int)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* count the nonzeros in each row of U */
+    /* ---------------------------------------------------------------------- */
+
+    for (row = 0 ; row < n ; row++)
+    {
+       Unz [row] = 0 ;
+    }
+    for (col = 0 ; col < n ; col++)
+    {
+       for (p = Up [col] ; p < Up [col+1] ; p++)
+       {
+           row = Ui [p] ;
+           Unz [row]++ ;
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* count the flops */
+    /* ---------------------------------------------------------------------- */
+
+    flop_count = 0.0 ;
+    for (k = 0 ; k < n ; k++)
+    {
+       /* off-diagonal nonzeros in column k of L: */
+       Lnz_k = Lp [k+1] - Lp [k] - 1 ;
+       Unz_k = Unz [k] - 1 ;
+       flop_count += (2 * Lnz_k * Unz_k) + Lnz_k ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return the result */
+    /* ---------------------------------------------------------------------- */
+
+    plhs [0] = mxCreateDoubleMatrix (1, 1, mxREAL) ;
+    pflop = mxGetPr (plhs [0]) ;
+    pflop [0] = flop_count ;
+}
+
diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack.m b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack.m
new file mode 100644 (file)
index 0000000..3285bb6
--- /dev/null
@@ -0,0 +1,44 @@
+function [out1, out2, out3, out4, out5] = umfpack (in1, in2, in3, in4, in5)
+% UMFPACK v4.3 is a MATLAB mexFunction for solving sparse linear systems.
+%
+% UMFPACK v4.3:                       |  MATLAB approximate equivalent:
+% ---------------------------------------------------------------------
+% x = umfpack (A, '\', b) ;           |  x = A \ b
+%                                     |
+% x = umfpack (b, '/', A) ;           |  x = b / A
+%                                     |
+% [L,U,P,Q] = umfpack (A) ;           |  [m,n] = size (A) ;
+%                                     |  I = speye (n) ;
+%                                     |  Q = I (:, colamd (A)) ;
+%                                     |  [L,U,P] = lu (A*Q) ;
+%                                     |
+% [L,U,P,Q,R] = umfpack (A) ;         |  [m,n] = size (A) ;
+%                                     |  I = speye (n) ;
+%                                     |  Q = I (:, colamd (A)) ;
+%                                     |  r = full (sum (abs (A), 2)) ;
+%                                     |  r (find (r == 0)) = 1 ;
+%                                     |  R = spdiags (r, 0, m, m) ;
+%                                     |  [L,U,P] = lu ((R\A)*Q) ;
+%                                     |
+% [P,Q,F,C] = umfpack (A, 'symbolic') |  [m,n] = size (A) ; 
+%                                     |  I = speye (n) ;
+%                                     |  Q = I (:, colamd (A)) ;
+%                                     |  [count,h,parent,post] = ...
+%                                     |  symbfact (A*Q, 'col') ;
+%
+% A must be sparse.  It can be complex, singular, and/or rectangular.  A must be
+% square for '/' or '\'.  b must be a full real or complex vector.  For
+% [L,U,P,Q,R] = umfpack (A), the factorization is L*U = P*(R\A)*Q.  If A has a
+% mostly symmetric nonzero pattern, then replace "colamd" with "amd" in the
+% MATLAB-equivalent column in the table above.  Type umfpack_details for more
+% information.
+%
+% See also: lu_normest, colamd, amd.
+% To use UMFPACK for an arbitrary b, see umfpack_solve.
+
+% UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.
+% Davis.  All Rights Reserved.  Type umfpack_details for License.
+
+help umfpack
+error ('umfpack mexFunction not found!  Use umfpack_make to compile umfpack.') ;
+
diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_btf.m b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_btf.m
new file mode 100644 (file)
index 0000000..a9da270
--- /dev/null
@@ -0,0 +1,129 @@
+function x = umfpack_btf (A, b, Control)
+% UMFPACK_BTF
+%
+% x = umfpack_btf (A, b, Control)
+%
+% solve Ax=b by first permuting the matrix A to block triangular form via dmperm
+% and then using UMFPACK to factorize each diagonal block.  Adjacent 1-by-1
+% blocks are merged into a single upper triangular block, and solved via
+% MATLAB's \ operator.  The Control parameter is optional (Type umfpack_details
+% and umfpack_report for details on its use).  A must be square.
+%
+% See also:  umfpack, umfpack_factorize, umfpack_details, dmperm
+
+% UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.
+% Davis.  All Rights Reserved.  Type umfpack_details for License.
+
+if (nargin < 2)
+    help umfpack_btf
+    error ('Usage: x = umfpack_btf (A, b, Control)') ;
+end
+
+[m n] = size (A) ;
+if (m ~= n)
+    help umfpack_btf
+    error ('umfpack_btf:  A must be square') ;
+end
+[m1 n1] = size (b) ;
+if (m1 ~= n)
+    help umfpack_btf
+    error ('umfpack_btf:  b has the wrong dimensions') ;
+end
+
+if (nargin < 3)
+    Control = umfpack ;
+end
+
+%-------------------------------------------------------------------------------
+% find the block triangular form
+%-------------------------------------------------------------------------------
+
+[p,q,r] = dmperm (A) ;
+nblocks = length (r) - 1 ;
+
+%-------------------------------------------------------------------------------
+% solve the system
+%-------------------------------------------------------------------------------
+
+if (nblocks == 1 | sprank (A) < n)
+
+    %---------------------------------------------------------------------------
+    % matrix is irreducible or structurally singular
+    %---------------------------------------------------------------------------
+
+    x = umfpack_solve (A, '\', b, Control) ;
+
+else
+
+    %---------------------------------------------------------------------------
+    % A (p,q) is in block triangular form
+    %---------------------------------------------------------------------------
+
+    b = b (p,:) ;
+    A = A (p,q) ;
+    x = zeros (size (b)) ;
+
+    %---------------------------------------------------------------------------
+    % merge adjacent singletons into a single upper triangular block
+    %---------------------------------------------------------------------------
+
+    [r, nblocks, is_triangular] = merge_singletons (r) ;
+
+    %---------------------------------------------------------------------------
+    % solve the system: x (q) = A\b
+    %---------------------------------------------------------------------------
+
+    for k = nblocks:-1:1
+
+       % get the kth block
+        k1 = r (k) ;
+        k2 = r (k+1) - 1 ;
+
+       % solve the system
+       x (k1:k2,:) = solver (A (k1:k2, k1:k2), b (k1:k2,:), ...
+           is_triangular (k), Control) ;
+
+        % off-diagonal block back substitution
+        b (1:k1-1,:) = b (1:k1-1,:) - A (1:k1-1, k1:k2) * x (k1:k2,:) ;
+
+    end
+
+    x (q,:) = x ;
+
+end
+
+%-------------------------------------------------------------------------------
+% merge_singletons
+%-------------------------------------------------------------------------------
+
+function [r, nblocks, is_triangular] = merge_singletons (r)
+%
+% Given r from [p,q,r] = dmperm (A), where A is square, return a modified r that
+% reflects the merger of adjacent singletons into a single upper triangular
+% block.  is_triangular (k) is 1 if the kth block is upper triangular.  nblocks
+% is the number of new blocks.
+
+nblocks = length (r) - 1 ;
+bsize = r (2:nblocks+1) - r (1:nblocks) ;
+t = [0 (bsize == 1)] ;
+z = (t (1:nblocks) == 0 & t (2:nblocks+1) == 1) | t (2:nblocks+1) == 0 ;
+y = [(find (z)) nblocks+1] ;
+r = r (y) ;
+nblocks = length (y) - 1 ;
+is_triangular = y (2:nblocks+1) - y (1:nblocks) > 1 ;
+
+%-------------------------------------------------------------------------------
+% solve Ax=b, but check for small and/or triangular systems
+%-------------------------------------------------------------------------------
+
+function x = solver (A, b, is_triangular, Control)
+if (is_triangular)
+    % back substitution only
+    x = A \ b ;
+elseif (size (A,1) < 4)
+    % a very small matrix, solve it as a dense linear system
+    x = full (A) \ b ;
+else
+    % solve it as a sparse linear system
+    x = umfpack_solve (A, '\', b, Control) ;
+end
diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_demo.m b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_demo.m
new file mode 100644 (file)
index 0000000..422a32f
--- /dev/null
@@ -0,0 +1,195 @@
+function umfpack_demo
+% UMFPACK DEMO
+%
+% A demo of UMFPACK for MATLAB.
+%
+% See also umfpack, umfpack_make, umfpack_details, umfpack_report,
+% and umfpack_simple.
+
+% UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.
+% Davis.  All Rights Reserved.  Type umfpack_details for License.
+
+%-------------------------------------------------------------------------------
+% get default control parameters
+%-------------------------------------------------------------------------------
+
+control = umfpack ;
+fprintf ('\nEnter the printing level for UMFPACK''s output statistics:\n') ;
+fprintf ('0: none, 1: errors only, 2: statistics, 4: print some of outputs\n') ;
+c = input ('5: print all output [default is 1]: ') ;
+if (isempty (c))
+    c = 1 ;
+end
+control (1) = c ;
+
+%-------------------------------------------------------------------------------
+% solve a simple system
+%-------------------------------------------------------------------------------
+
+fprintf ('\n--------------------------------------------------------------\n') ;
+fprintf ('Factor and solve a small system, Ax=b, using default parameters\n') ;
+if (control (1) > 1)
+    fprintf ('(except for verbose printing enabled)\n') ;
+end
+
+load west0067
+A = Problem.A ;
+n = size (A, 1) ;
+b = rand (n, 1) ;
+
+fprintf ('Solving Ax=b via UMFPACK:\n') ;
+[xu, info] = umfpack (A, '\', b, control) ;
+x = xu ;
+
+fprintf ('Solving Ax=b via MATLAB:\n') ;
+xm = A\b ;
+x = xm ;
+
+fprintf ('Difference between UMFPACK and MATLAB solution: %g\n', ...
+    norm (xu - xm, Inf)) ;
+
+%-------------------------------------------------------------------------------
+% spy the results
+%-------------------------------------------------------------------------------
+
+figure (1)
+clf
+
+subplot (2,3,1)
+spy (A)
+title ('The matrix A') ;
+
+subplot (2,3,2)
+[P1, Q1, Fr, Ch, Info] = umfpack (A, 'symbolic') ;
+treeplot (Fr (1:end-1,2)') ;
+title ('Supernodal column elimination tree') ;
+
+subplot (2,3,3)
+spy (P1 * A * Q1)
+title ('A, with initial row and column order') ;
+
+subplot (2,3,4)
+fprintf ('\n--------------------------------------------------------------\n') ;
+fprintf ('\nFactorizing [L, U, P, Q, R] = umfpack (A)\n') ;
+[L, U, P, Q, R] = umfpack (A) ;
+spy (P*A*Q)
+title ('A, with final row/column order') ;
+
+fprintf ('\nP * (R\\A) * Q - L*U should be zero:\n') ;
+fprintf ('norm (P*(R\\A)*Q - L*U, 1) = %g (exact) %g (estimated)\n', ...
+    norm (P * (R\A) * Q - L*U, 1), lu_normest (P * (R\A) * Q,  L, U)) ;
+
+fprintf ('\nSolution to Ax=b via UMFPACK factorization:\n') ;
+fprintf ('x = Q * (U \\ (L \\ (P * (R \\ b))))\n') ;
+xu = Q * (U \ (L \ (P * (R \ b)))) ;
+x = xu ;
+
+fprintf ('\nUMFPACK flop count: %d\n', luflop (L, U)) ;
+
+subplot (2,3,5)
+spy (spones (L) + spones (U))
+title ('UMFPACK LU factors') ;
+
+subplot (2,3,6)
+fprintf ('\nFactorizing [L, U, P] = lu (A (:, q))\n') ;
+fprintf ('If you are using a version of MATLAB prior to V6.0, then the\n') ;
+fprintf ('following statement (q = colamd (A)) may fail.  Either download\n');
+fprintf ('colamd from http://www.cise.ufl.edu/research/sparse, upgrade to\n') ;
+fprintf ('MATLAB V6.0 or later, or replace the statement with\n') ;
+fprintf ('q = colmmd (A) ;\n') ;
+try
+    q = colamd (A) ;
+catch
+    fprintf ('\n *** colamd not found, using colmmd instead *** \n') ;
+    q = colmmd (A) ;
+end
+[L, U, P] = lu (A (:,q)) ;
+spy (spones (L) + spones (U))
+title ('MATLAB LU factors') ;
+
+fprintf ('\nSolution to Ax=b via MATLAB factorization:\n') ;
+fprintf ('x = U \\ (L \\ (P * b)) ; x (q) = x ;\n') ;
+xm = U \ (L \ (P * b)) ;
+xm (q) = xm ;
+
+fprintf ('Difference between UMFPACK and MATLAB solution: %g\n', ...
+    norm (xu - xm, Inf)) ;
+
+fprintf ('\nMATLAB LU flop count: %d\n', luflop (L, U)) ;
+
+%-------------------------------------------------------------------------------
+% solve A'x=b
+%-------------------------------------------------------------------------------
+
+fprintf ('\n--------------------------------------------------------------\n') ;
+fprintf ('Solve A''x=b:\n') ;
+
+fprintf ('Solving A''x=b via UMFPACK:\n') ;
+[xu, info] = umfpack (b', '/', A, control) ;
+xu = xu' ;
+
+fprintf ('Solving A''x=b via MATLAB:\n') ;
+xm = (b'/A)' ;
+x = xm ;
+
+fprintf ('Difference between UMFPACK and MATLAB solution: %g\n', ...
+    norm (xu - xm, Inf)) ;
+
+%-------------------------------------------------------------------------------
+% factor A' and then solve Ax=b using the factors of A'
+%-------------------------------------------------------------------------------
+
+fprintf ('\n--------------------------------------------------------------\n') ;
+fprintf ('Compute C = A'', and compute the LU factorization of C.\n') ;
+fprintf ('Factorizing A'' can sometimes be better than factorizing A itself\n');
+fprintf ('(less work and memory usage).  Solve C''x=b; the solution is the\n') ;
+fprintf ('same as the solution to Ax=b for the original A.\n');
+
+C = A' ;
+
+% factorize C (P,Q) = L*U
+[L, U, P, Q, R, info] = umfpack (C, control) ;
+
+fprintf ('\nP * (R\\C) * Q - L*U should be zero:\n') ;
+fprintf ('norm (P*(R\\C)*Q - L*U, 1) = %g (exact) %g (estimated)\n', ...
+    norm (P * (R\C) * Q - L*U, 1), lu_normest (P * (R\C) * Q,  L, U)) ;
+
+fprintf ('\nSolution to Ax=b via UMFPACK, using the factors of C:\n') ;
+fprintf ('x = R \\ (P'' * (L'' \\ (U'' \\ (Q'' * b)))) ;\n') ;
+xu = R \ (P' * (L' \ (U' \ (Q' * b)))) ;
+x = xu ;
+
+fprintf ('Solution to Ax=b via MATLAB:\n') ;
+xm = A\b ;
+x = xm ;
+
+fprintf ('Difference between UMFPACK and MATLAB solution: %g\n', ...
+    norm (xu - xm, Inf)) ;
+
+%-------------------------------------------------------------------------------
+% solve Ax=B
+%-------------------------------------------------------------------------------
+
+fprintf ('\n--------------------------------------------------------------\n') ;
+fprintf ('\nSolve AX=B, where B is n-by-10, and sparse\n') ;
+B = sprandn (n, 10, 0.05) ;
+XU = umfpack_solve (A, '\', B, control) ;
+XM = A\B ;
+
+fprintf ('Difference between UMFPACK and MATLAB solution: %g\n', ...
+    norm (XU - XM, Inf)) ;
+
+fprintf ('\n--------------------------------------------------------------\n') ;
+fprintf ('\nSolve AX=B, where B is n-by-10, and sparse, using umfpack_btf\n') ;
+XU = umfpack_btf (A, B, control) ;
+
+fprintf ('Difference between UMFPACK and MATLAB solution: %g\n', ...
+    norm (XU - XM, Inf)) ;
+
+fprintf ('\n--------------------------------------------------------------\n') ;
+fprintf ('\nSolve A''X=B, where B is n-by-10, and sparse\n') ;
+XU = umfpack_solve (B', '/', A, control) ;
+XM = B'/A ;
+
+fprintf ('Difference between UMFPACK and MATLAB solution: %g\n', ...
+    norm (XU - XM, Inf)) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_demo.m.out b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_demo.m.out
new file mode 100644 (file)
index 0000000..10adebe
--- /dev/null
@@ -0,0 +1,72 @@
+>> umfpack_demo
+
+Enter the printing level for UMFPACK's output statistics:
+0: none, 1: errors only, 2: statistics, 4: print some of outputs
+5: print all output [default is 1]: 
+
+--------------------------------------------------------------
+Factor and solve a small system, Ax=b, using default parameters
+Solving Ax=b via UMFPACK:
+Solving Ax=b via MATLAB:
+Difference between UMFPACK and MATLAB solution: 1.24345e-14
+
+--------------------------------------------------------------
+
+Factorizing [L, U, P, Q, R] = umfpack (A)
+
+P * (R\A) * Q - L*U should be zero:
+norm (P*(R\A)*Q - L*U, 1) = 4.2068e-16 (exact) 3.74627e-16 (estimated)
+
+Solution to Ax=b via UMFPACK factorization:
+x = Q * (U \ (L \ (P * (R \ b))))
+
+UMFPACK flop count: 2362
+
+Factorizing [L, U, P] = lu (A (:, q))
+If you are using a version of MATLAB prior to V6.0, then the
+following statement (q = colamd (A)) may fail.  Either download
+colamd from http://www.cise.ufl.edu/research/sparse, upgrade to
+MATLAB V6.0 or later, or replace the statement with
+q = colmmd (A) ;
+
+Solution to Ax=b via MATLAB factorization:
+x = U \ (L \ (P * b)) ; x (q) = x ;
+Difference between UMFPACK and MATLAB solution: 1.37668e-14
+
+MATLAB LU flop count: 3164
+
+--------------------------------------------------------------
+Solve A'x=b:
+Solving A'x=b via UMFPACK:
+Solving A'x=b via MATLAB:
+Difference between UMFPACK and MATLAB solution: 3.10862e-15
+
+--------------------------------------------------------------
+Compute C = A', and compute the LU factorization of C.
+Factorizing A' can sometimes be better than factorizing A itself
+(less work and memory usage).  Solve C'x=b; the solution is the
+same as the solution to Ax=b for the original A.
+
+P * (R\C) * Q - L*U should be zero:
+norm (P*(R\C)*Q - L*U, 1) = 1.31839e-16 (exact) 6.41848e-17 (estimated)
+
+Solution to Ax=b via UMFPACK, using the factors of C:
+x = R \ (P' * (L' \ (U' \ (Q' * b)))) ;
+Solution to Ax=b via MATLAB:
+Difference between UMFPACK and MATLAB solution: 1.77636e-14
+
+--------------------------------------------------------------
+
+Solve AX=B, where B is n-by-10, and sparse
+Difference between UMFPACK and MATLAB solution: 2.88198e-14
+
+--------------------------------------------------------------
+
+Solve AX=B, where B is n-by-10, and sparse, using umfpack_btf
+Difference between UMFPACK and MATLAB solution: 9.79736e-14
+
+--------------------------------------------------------------
+
+Solve A'X=B, where B is n-by-10, and sparse
+Difference between UMFPACK and MATLAB solution: 1.05244e-13
+>> diary off
diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_details.m b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_details.m
new file mode 100644 (file)
index 0000000..315de17
--- /dev/null
@@ -0,0 +1,155 @@
+function [out1, out2, out3, out4, out5] = umfpack (in1, in2, in3, in4, in5)
+% UMFPACK v4.3:  details on each usage.
+%
+% Factor or solve a sparse linear system, returning either the solution x to
+% Ax=b or A'x'=b', the factorization LU=PAQ, or LU=P(R\A)Q.  A must be sparse.
+% For the solve, A must be square and b must be a dense n-by-1 vector.  For LU
+% factorization, A can be rectangular.  In both cases, A and/or b can be real
+% or complex.
+%
+% UMFPACK analyzes the matrix and selects one of three strategies to factorize
+% the matrix.  It first finds a set of k initial pivot entries of zero Markowitz
+% cost.  This forms the first k rows and columns of L and U.  The remaining
+% submatrix S is then analyzed, based on the symmetry of the nonzero pattern of
+% the submatrix and the values on the diagaonal.  The strategies include:
+%
+%      (1) unsymmetric:  use a COLAMD pre-ordering, a column elimination tree
+%          post-ordering, refine the column ordering during factorization,
+%          and make no effort at selecting pivots on the diagonal.
+%      (2) 2-by-2:  like the symmetric strategy (see below), except that local
+%          row permutations are first made to attempt to place large entries
+%          on the diagonal.
+%      (3) symmetric:  use an AMD pre-ordering on the matrix S+S', an
+%          elimination tree post-ordering, do not refine the column ordering
+%          during factorization, and attempt to select pivots on the diagonal.
+%
+% Each of the following uses of umfpack (except for "Control = umfpack") is
+% stand-alone.  That is, no call to umfpack is required for any subsequent
+% call.  In each usage, the Info output argument is optional.
+%
+% Usage:
+%
+% [x, Info] = umfpack (A, '\', b) ;
+% [x, Info] = umfpack (A, '\', b, Control) ;
+% [x, Info] = umfpack (A, Qinit, '\', b, Control) ;
+% [x, Info] = umfpack (A, Qinit, '\', b) ;
+%
+%       Solves Ax=b (similar to x = A\b in MATLAB).
+%
+% [x, Info] = umfpack (b, '/', A) ;
+% [x, Info] = umfpack (b, '/', A, Control) ;
+% [x, Info] = umfpack (b, '/', A, Qinit) ;
+% [x, Info] = umfpack (b, '/', A, Qinit, Control) ;
+%
+%       Solves A'x'=b' (similar to x = b/A in MATLAB).
+%
+% [L, U, P, Q, R, Info] = umfpack (A) ;
+% [L, U, P, Q, R, Info] = umfpack (A, Control) ;
+% [L, U, P, Q, R, Info] = umfpack (A, Qinit) ;
+% [L, U, P, Q, R, Info] = umfpack (A, Qinit, Control) ;
+%
+%       Returns the LU factorization of A.  P and Q are returned as permutation
+%       matrices.  R is a diagonal sparse matrix of scale factors for the rows
+%      of A, L is lower triangular, and U is upper triangular.  The
+%      factorization is L*U = P*(R\A)*Q.  You can turn off scaling by setting
+%      Control (17) to zero (in which case R = speye (m)), or by using the
+%      following syntaxes (in which case Control (17) is ignored):
+%
+% [L, U, P, Q] = umfpack (A) ;
+% [L, U, P, Q] = umfpack (A, Control) ;
+% [L, U, P, Q] = umfpack (A, Qinit) ;
+% [L, U, P, Q] = umfpack (A, Qinit, Control) ;
+%
+%       Same as above, except that no row scaling is performed.  The Info array
+%      is not returned, either.
+%
+% [P1, Q1, Fr, Ch, Info] = umfpack (A, 'symbolic') ;
+% [P1, Q1, Fr, Ch, Info] = umfpack (A, 'symbolic', Control) ;
+% [P1, Q1, Fr, Ch, Info] = umfpack (A, Qinit, 'symbolic') ;
+% [P1, Q1, Fr, Ch, Info] = umfpack (A, Qinit, 'symbolic', Control);
+%
+%       Performs only the fill-reducing column pre-ordering (including the
+%       elimination tree post-ordering) and symbolic factorization.  Q1 is the
+%      initial column permutation (either from colamd, amd, or the input
+%      ordering Qinit), possibly followed by a column elimination tree post-
+%      ordering or a symmetric elimination tree post-ordering, depending on
+%      the strategy used.
+%
+%      For the unsymmetric strategy, P1 is the row ordering induced by Q1
+%      (row-merge order). For the 2-by-2 strategy, P1 is the row ordering that
+%      places large entries on the diagonal of P1*A*Q1.  For the symmetric
+%      strategy, P1 = Q1.
+%
+%       Fr is a (nfr+1)-by-4 array containing information about each frontal
+%       matrix, where nfr <= n is the number of frontal matrices.  Fr (:,1) is
+%       the number of pivot columns in each front, and Fr (:,2) is the parent
+%       of each front in the supercolumn elimination tree.  Fr (k,2) is zero if
+%       k is a root.  The first Fr (1,1) columns of P1*A*Q1 are the pivot
+%       columns for the first front, the next Fr (2,1) columns of P1*A*Q1
+%       are the pivot columns for the second front, and so on.
+%
+%      For the unsymmetric strategy, Fr (:,3) is the row index of the first
+%      row in P1*A*Q1 whose leftmost nonzero entry is in a pivot column for
+%      the kth front.  Fr (:,4) is the leftmost descendent of the kth front.
+%      Rows in the range Fr (Fr (k,4),3) to Fr (k+1,3)-1 form the entire set
+%      of candidate pivot rows for the kth front (some of these will typically
+%      have been selected as pivot rows of fronts Fr (k,3) to k-1, before the
+%      factorization reaches the kth front.  If front k is a leaf node, then
+%      Fr (k,4) is k.
+%
+%       Ch is a (nchains+1)-by-3 array containing information about each "chain"
+%       (unifrontal sequence) of frontal matrices, and where nchains <= nfr
+%       is the number of chains.  The ith chain consists of frontal matrices.
+%       Chain (i,1) to Chain (i+1,1)-1, and the largest front in chain i is
+%       Chain (i,2)-by-Chain (i,3).
+%
+%       This use of umfpack is not required to factor or solve a linear system
+%       in MATLAB.  It analyzes the matrix A and provides information only.
+%       The MATLAB statement "treeplot (Fr (:,2)')" plots the column elimination
+%       tree.
+%
+% Control = umfpack ;
+%
+%       Returns a 20-by-1 vector of default parameter settings for umfpack.
+%
+% umfpack_report (Control, Info) ;
+%
+%       Prints the current Control settings, and Info
+%
+% If present, Qinit is a user-supplied 1-by-n permutation vector.  It is an
+% initial fill-reducing column pre-ordering for A; if not present, then colamd
+% or amd are used instead.  If present, Control is a user-supplied 20-by-1
+% array.   Control and Info are optional; if Control is not present, defaults
+% are used.  If a Control entry is NaN, then the default is used for that entry.
+%
+% UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.
+% Davis.  All Rights Reserved.
+% 
+% UMFPACK License:
+% 
+%     Your use or distribution of UMFPACK or any modified version of
+%     UMFPACK implies that you agree to this License.
+% 
+%     THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
+%     EXPRESSED OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+% 
+%     Permission is hereby granted to use or copy this program, provided
+%     that the Copyright, this License, and the Availability of the original
+%     version is retained on all copies.  User documentation of any code that
+%     uses UMFPACK or any modified version of UMFPACK code must cite the
+%     Copyright, this License, the Availability note, and "Used by permission."
+%     Permission to modify the code and to distribute modified code is granted,
+%     provided the Copyright, this License, and the Availability note are
+%     retained, and a notice that the code was modified is included.  This
+%     software was developed with support from the National Science Foundation,
+%     and is provided to you free of charge.
+% 
+% Availability: http://www.cise.ufl.edu/research/sparse/umfpack
+%
+% See also umfpack, umfpack_make, umfpack_report,
+%    umfpack_demo, and umfpack_simple.
+
+more on
+help umfpack_details
+more off
+
diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_make.m b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_make.m
new file mode 100644 (file)
index 0000000..ca239a9
--- /dev/null
@@ -0,0 +1,356 @@
+function umfpack_make
+% UMFPACK_MAKE
+%
+% Compiles the UMFPACK mexFunction and then runs a simple demo.
+%
+% UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.
+% Davis.  All Rights Reserved.  Type umfpack_details for License.
+%
+% See also: umfpack, umfpack_details, umfpack_report, umfpack_demo, and
+% umfpack_simple.
+
+help umfpack_make
+
+fprintf ('\n--------------------------------------------------------------\n') ;
+fprintf ('Now compiling the UMFPACK and AMD mexFunctions.\n') ;
+fprintf ('--------------------------------------------------------------\n') ;
+
+try
+    % ispc does not appear in MATLAB 5.3
+    pc = ispc ;
+catch
+    % if ispc fails, assume we aren't on a Windows PC.
+    pc = 0 ;
+end
+
+obj = 'o' ;
+blas_lib = '' ;
+if (pc)
+    obj = 'obj' ;
+end
+
+%-------------------------------------------------------------------------------
+% BLAS option
+%-------------------------------------------------------------------------------
+
+msg = [ ...
+    '\nUsing the BLAS is faster, but might not compile correctly.\n', ...
+    'If you get an error stating that dgemm, dgemv, dger, zgemm,\n', ...
+    'zgemv, and/or zger are not defined, then recompile without the\n', ...
+    'BLAS.  You can ignore warnings that these routines are implicitly\n', ...
+    'declared.\n\nPlease select one of the following options: \n', ...
+    '   1:  attempt to compile with the BLAS (default)\n', ...
+    '   2:  do not use the BLAS\n'] ;
+fprintf (msg) ;
+blas = input (': ') ;
+if (isempty (blas))
+    blas = 1 ;
+end
+if (blas == 1)
+    % try to link to MATLAB's built-in BLAS
+    blas = '' ;
+    if (pc)
+        % the default lcc compiler needs this library to access the BLAS
+        blas_lib = ' libmwlapack.lib' ;
+        msg = [ ...
+        '\nCheck to see if you have a file called libmwlapack.lib in the\n', ...
+        '<matlab>\\extern\\lib\\win32\\lcc\\ directory, where <matlab> is ', ...
+        'the\ndirectory where MATLAB is installed.  If a file of that ', ...
+        'name is already\nthere, then you don''t have to do anything.  ', ...
+        'Otherwise, you must first\ncopy the libmwlapack.lib file from ', ...
+        'the umfpack\\lcc_lib\\ directory to the\n', ...
+        '<matlab>\\extern\\lib\\win32\\lcc\\ directory.  Next, type\n\n', ...
+        '    mex -setup\n\n', ...
+        'at the MATLAB prompt, and ask MATLAB to select the lcc compiler.  ',...
+        'You can skip\nall of this if you have already done it, or have ', ...
+        'configured mex to use\na different compiler.  If you are using ', ...
+        'Norton anti-virus software on Windows\n98SE, then you need to ', ...
+        'exit MATLAB, turn off virus checking, and restart MATLAB\n', ...
+        'before you can use the mex command or compile UMFPACK.\n', ...
+        'You may also need to turn off virus checking in other cases.\n', ...
+        '\nHit enter to continue, or type control-C if you do not wish to '] ;
+        fprintf (msg) ;
+        input ('proceed: ') ;
+    end
+    fprintf ('\nUsing the BLAS (recommended).\n') ;
+else
+    % No BLAS
+    fprintf ('\nNot using the BLAS.  UMFPACK will be slow.\n') ;
+    blas = ' -DNBLAS' ;
+end
+
+%-------------------------------------------------------------------------------
+% -DNUTIL option (using utMalloc or mxMalloc)
+%-------------------------------------------------------------------------------
+
+utils = '' ;
+
+if (~pc)
+    msg = [ ...
+    '--------------------------------------------------------------\n', ...
+    '\nUMFPACK uses MATLAB''s memory allocation routines.  The internal', ...
+    '\nutMalloc, utFree, and utRealloc allow for better use of memory,', ...
+    '\nbut they are internal utility routines that are not documented.\n', ...
+    'Thus, they might not always work.  Using mxMalloc, mxFree, and\n', ...
+    'mxRealloc works, but UMFPACK might run out of memory when solving\n', ...
+    'problems that it could otherwise solve.  Try using the default.\n', ...
+    'If you get an error stating that utMalloc, utFree, and/or\n', ...
+    'utRealloc are not defined, then recompile with the mx* routines.\n', ...
+    '\nPlease select one of the following options:\n', ...
+    '    1:  attempt to use the ut* routines (default)\n', ...
+    '    2:  use the standard mx* routines\n'] ;
+    fprintf (msg) ;
+    utils = input (': ') ;
+    if (isempty (utils))
+       utils = 1 ;
+    end
+    if (utils == 2)
+        fprintf ('\nNot using utMalloc, utFree, or utRealloc\n') ;
+        utils = ' -DNUTIL' ;
+    else
+        fprintf ('\nUsing utMalloc, utFree, and utRealloc\n') ;
+        utils = '' ;
+    end
+end
+
+%-------------------------------------------------------------------------------
+% -DNPOSIX option (for sysconf and times timer routines)
+%-------------------------------------------------------------------------------
+
+posix = '' ;
+
+if (~pc)
+    msg = [ ...
+    '--------------------------------------------------------------\n', ...
+    '\nUMFPACK can use the POSIX routines sysconf () and times ()\n', ...
+    'to provide CPU time and wallclock time statistics.  If you do not\n', ...
+    'have a POSIX-compliant operating system, then UMFPACK won''t\n', ...
+    'compile.  If you don''t know which option to pick, try the\n', ...
+    'default.  If you get an error saying that sysconf and/or times\n', ...
+    'are not defined, then recompile with the non-POSIX option.\n', ...
+    '\nPlease select one of the following options:\n', ...
+    '    1:  use POSIX sysconf and times routines (default)\n', ...
+    '    2:  do not use POSIX routines\n'] ;
+    fprintf (msg) ;
+    posix = input (': ') ;
+    if (isempty (posix))
+       posix = 1 ;
+    end
+    if (posix == 2)
+        fprintf ('\nNot using POSIX sysconf and times routines.\n') ;
+        posix = ' -DNPOSIX' ;
+    else
+        fprintf ('\nUsing POSIX sysconf and times routines.\n') ;
+        posix = '' ;
+    end
+end
+
+%-------------------------------------------------------------------------------
+% mex command
+%-------------------------------------------------------------------------------
+
+umfdir = sprintf ('..%sSource%s', filesep, filesep) ;
+amddir = sprintf ('..%s..%sAMD%sSource%s', filesep, filesep, filesep, filesep) ;
+incdir = sprintf ( ...
+' -I..%sInclude -I..%sSource -I..%s..%sAMD%sInclude -I..%s..%sAMD%sSource', ...
+filesep,filesep,  filesep, filesep, filesep, filesep, filesep, filesep) ;
+
+mx = sprintf ('mex -inline -O%s%s%s%s', blas, utils, posix, incdir) ;
+msg = [ ...
+    '--------------------------------------------------------------\n', ...
+    '\nCompile options:\n%s\nNow compiling.  Please wait.\n'] ;
+fprintf (msg, mx) ;
+
+% The following is adapted from GNUmakefile
+
+%-------------------------------------------------------------------------------
+% source files
+%-------------------------------------------------------------------------------
+
+% non-user-callable umf_*.[ch] files:
+umfch = { 'assemble', 'blas3_update', ...
+        'build_tuples', 'create_element', ...
+        'dump', 'extend_front', 'garbage_collection', ...
+        'get_memory', 'init_front', 'kernel', ...
+        'kernel_init', 'kernel_wrapup', ...
+        'local_search', 'lsolve', 'ltsolve', ...
+        'mem_alloc_element', 'mem_alloc_head_block', ...
+        'mem_alloc_tail_block', 'mem_free_tail_block', ...
+        'mem_init_memoryspace', ...
+        'report_vector', 'row_search', 'scale_column', ...
+        'set_stats', 'solve', 'symbolic_usage', 'transpose', ...
+        'tuple_lengths', 'usolve', 'utsolve', 'valid_numeric', ...
+        'valid_symbolic', 'grow_front', 'start_front', '2by2', ...
+       'store_lu', 'scale' } ;
+
+% non-user-callable umf_*.[ch] files, int versions only (no real/complex):
+umfint = { 'analyze', 'apply_order', 'colamd', 'free', 'fsize', ...
+        'is_permutation', 'malloc', 'realloc', 'report_perm', ...
+       'singletons' } ;
+
+% non-user-callable and user-callable amd_*.[ch] files (int versions only):
+amd = { 'aat', '1', '2', 'dump', 'postorder', 'post_tree', 'defaults', ...
+        'order', 'control', 'info', 'valid' } ;
+
+% user-callable umfpack_*.[ch] files (real/complex):
+user = { 'col_to_triplet', 'defaults', 'free_numeric', ...
+        'free_symbolic', 'get_numeric', 'get_lunz', ...
+        'get_symbolic', 'numeric', 'qsymbolic', ...
+        'report_control', 'report_info', 'report_matrix', ...
+        'report_numeric', 'report_perm', 'report_status', ...
+        'report_symbolic', 'report_triplet', ...
+        'report_vector', 'solve', 'symbolic', ...
+        'transpose', 'triplet_to_col', 'scale' ...
+       'load_numeric', 'save_numeric', 'load_symbolic', 'save_symbolic' } ;
+
+% user-callable umfpack_*.[ch], only one version
+generic = { 'timer', 'tictoc' } ;
+
+M = cell (0) ;
+
+%-------------------------------------------------------------------------------
+% Create the umfpack and amd mexFunctions for MATLAB (int versions only)
+%-------------------------------------------------------------------------------
+
+for k = 1:length(umfint)
+    M = make (M, '%s -DDINT -c %sumf_%s.c', 'umf_%s.%s', 'umf_%s_%s.%s', ...
+        mx, umfint {k}, umfint {k}, 'm', obj, umfdir) ;
+end
+
+rules = { [mx ' -DDINT'] , [mx ' -DZINT'] } ;
+kinds = { 'md', 'mz' } ;
+
+for what = 1:2 
+
+    rule = rules {what} ;
+    kind = kinds {what} ;
+
+    M = make (M, '%s -DCONJUGATE_SOLVE -c %sumf_%s.c', 'umf_%s.%s', ...
+        'umf_%s_%s.%s', rule, 'ltsolve', 'lhsolve', kind, obj, umfdir) ;
+
+    M = make (M, '%s -DCONJUGATE_SOLVE -c %sumf_%s.c', 'umf_%s.%s', ...
+        'umf_%s_%s.%s', rule, 'utsolve', 'uhsolve', kind, obj, umfdir) ;
+
+    M = make (M, '%s -DDO_MAP -c %sumf_%s.c', 'umf_%s.%s', ...
+        'umf_%s_%s_map_nox.%s', rule, 'triplet', 'triplet', kind, obj, umfdir) ;
+
+    M = make (M, '%s -DDO_VALUES -c %sumf_%s.c', 'umf_%s.%s', ...
+        'umf_%s_%s_nomap_x.%s', rule, 'triplet', 'triplet', kind, obj, umfdir) ;
+
+    M = make (M, '%s -c %sumf_%s.c', 'umf_%s.%s',  ...
+        'umf_%s_%s_nomap_nox.%s', rule, 'triplet', 'triplet', kind, obj, ...
+       umfdir) ;
+
+    M = make (M, '%s -DDO_MAP -DDO_VALUES -c %sumf_%s.c', 'umf_%s.%s', ...
+        'umf_%s_%s_map_x.%s', rule, 'triplet', 'triplet', kind, obj, umfdir) ;
+
+    M = make (M, '%s -DFIXQ -c %sumf_%s.c', 'umf_%s.%s', ...
+       'umf_%s_%s_fixq.%s', rule, 'assemble', 'assemble', kind, obj, umfdir) ;
+
+    M = make (M, '%s -DDROP -c %sumf_%s.c', 'umf_%s.%s', ...
+       'umf_%s_%s_drop.%s', rule, 'store_lu', 'store_lu', kind, obj, umfdir) ;
+
+    for k = 1:length(umfch)
+        M = make (M, '%s -c %sumf_%s.c', 'umf_%s.%s', 'umf_%s_%s.%s', ...
+            rule, umfch {k}, umfch {k}, kind, obj, umfdir) ;
+    end
+
+    M = make (M, '%s -DWSOLVE -c %sumfpack_%s.c', 'umfpack_%s.%s', ...
+        'umfpack_%s_w%s.%s', rule, 'solve', 'solve', kind, obj, umfdir) ;
+
+    for k = 1:length(user)
+        M = make (M, '%s -c %sumfpack_%s.c', 'umfpack_%s.%s', ...
+            'umfpack_%s_%s.%s', rule, user {k}, user {k}, kind, obj, umfdir) ;
+    end
+end
+
+for k = 1:length(generic)
+    M = make (M, '%s -c %sumfpack_%s.c', 'umfpack_%s.%s', ...
+       'umfpack_%s_%s.%s', mx, generic {k}, generic {k}, 'm', obj, umfdir) ;
+end
+
+%----------------------------------------
+% AMD routines (int only)
+%----------------------------------------
+
+for k = 1:length(amd)
+    M = make (M, '%s -DDINT -c %samd_%s.c', 'amd_%s.%s', 'amd_%s_%s.%s', ...
+        mx, amd {k}, amd {k}, 'm', obj, amddir) ;
+end
+
+%----------------------------------------
+% compile the umfpack mexFunction
+%----------------------------------------
+
+C = sprintf ('%s -output umfpack umfpackmex.c', mx) ;
+for i = 1:length (M)
+    C = [C ' ' (M {i})] ;
+end
+C = [C ' ' blas_lib] ;
+cmd (C) ;
+
+%----------------------------------------
+% delete the object files
+%----------------------------------------
+
+for i = 1:length (M)
+    rmfile (M {i}) ;
+end
+
+%----------------------------------------
+% compile the luflop mexFunction
+%----------------------------------------
+
+cmd (sprintf ('%s -output luflop luflopmex.c', mx)) ;
+
+fprintf ('\n\nCompilation has completed.  Now trying the umfpack_simple demo.\n');
+umfpack_simple
+
+%-------------------------------------------------------------------------------
+% rmfile:  delete a file, but only if it exists
+%-------------------------------------------------------------------------------
+
+function rmfile (file)
+if (length (dir (file)) > 0)
+    delete (file) ;
+end
+
+%-------------------------------------------------------------------------------
+% cpfile:  copy the src file to the filename dst, overwriting dst if it exists
+%-------------------------------------------------------------------------------
+
+function cpfile (src, dst)
+rmfile (dst)
+if (length (dir (src)) == 0)
+    help umfpack_make
+    error (sprintf ('File does not exist: %s\n', src)) ;
+end
+copyfile (src, dst) ;
+
+%-------------------------------------------------------------------------------
+% mvfile:  move the src file to the filename dst, overwriting dst if it exists
+%-------------------------------------------------------------------------------
+
+function mvfile (src, dst)
+cpfile (src, dst) ;
+rmfile (src) ;
+
+%-------------------------------------------------------------------------------
+% cmd:  display and execute a command
+%-------------------------------------------------------------------------------
+
+function cmd (s)
+fprintf ('.') ;
+eval (s) ;
+
+%-------------------------------------------------------------------------------
+% make:  execute a "make" command for a source file
+%-------------------------------------------------------------------------------
+
+function M = make (M, s, src, dst, rule, file1, file2, kind, obj, srcdir)
+cmd (sprintf (s, rule, srcdir, file1)) ;
+src = sprintf (src, file1, obj) ;
+dst = sprintf (dst, kind, file2, obj) ;
+mvfile (src, dst) ;
+M {end + 1} = dst ;
+
diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_report.m b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_report.m
new file mode 100644 (file)
index 0000000..10d661a
--- /dev/null
@@ -0,0 +1,346 @@
+function umfpack_report (Control, Info)
+% UMFPACK_REPORT
+%
+%       umfpack_report (Control, Info) ;
+%
+% Prints the current Control settings for umfpack, and the statistical
+% information returned by umfpack in the Info array.  If Control is
+% an empty matrix, then the default control settings are printed.
+%
+% Control is 20-by-1, and Info is 90-by-1.  Not all entries are used.
+%
+% Alternative usages:
+%
+%       umfpack_report ([ ], Info) ;    print the default control parameters
+%                                       and the Info array.
+%       umfpack_report (Control) ;      print the control parameters only.
+%       umfpack_report ;                print the default control parameters
+%                                       and an empty Info array.
+%
+% See also umfpack, umfpack_make, umfpack_details,
+% umfpack_demo, and umfpack_simple.
+
+% UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.
+% Davis.  All Rights Reserved.  See ../README for License.
+
+%-------------------------------------------------------------------------------
+% get inputs, use defaults if input arguments not present
+%-------------------------------------------------------------------------------
+
+% The contents of Control and Info are defined in umfpack.h
+if (nargin < 1)
+    Control = [] ;
+end
+if (nargin < 2)
+    Info = [] ;
+end
+if (isempty (Control))
+    Control = umfpack ;
+end
+if (isempty (Info))
+    Info = [ 0 (-ones (1, 89)) ] ;
+end
+
+%-------------------------------------------------------------------------------
+% control settings
+%-------------------------------------------------------------------------------
+
+fprintf ('\nUMFPACK Version 4.3:  Control settings:\n\n') ;
+fprintf ('    Control (1): print level: %d\n', Control (1)) ;
+fprintf ('    Control (2): dense row parameter:    %g\n', Control (2)) ;
+fprintf ('       "dense" rows have    > max (16, (%g)*16*sqrt(n_col)) entries\n', Control (2)) ;
+fprintf ('    Control (3): dense column parameter: %g\n', Control (3)) ;
+fprintf ('       "dense" columns have > max (16, (%g)*16*sqrt(n_row)) entries\n', Control (3)) ;
+fprintf ('    Control (4): pivot tolerance: %g\n', Control (4)) ;
+fprintf ('    Control (5): max block size for dense matrix kernels: %d\n', Control (5)) ;
+prstrat ('    Control (6): strategy: %g ', Control (6)) ;
+fprintf ('    Control (7): initial allocation ratio: %g\n', Control (7)) ;
+fprintf ('    Control (8): max iterative refinement steps: %d\n', Control (8)) ;
+fprintf ('    Control (13): 2-by-2 pivot tolerance: %g\n', Control (13)) ;
+fprintf ('    Control (14): Q fixed during numeric factorization: %g ', Control (14)) ;
+if (Control (14) > 0)
+    fprintf ('(yes)\n') ;
+elseif (Control (14) < 0)
+    fprintf ('(no)\n') ;
+else
+    fprintf ('(auto)\n') ;
+end
+fprintf ('    Control (15): AMD dense row/column parameter: %g\n', Control (15)) ;
+fprintf ('       "dense" rows/columns in A+A'' have > max (16, (%g)*sqrt(n)) entries.\n', Control (15)) ;
+fprintf ('        Only used if the AMD ordering is used.\n') ;
+fprintf ('    Control (16): diagonal pivot tolerance: %g\n', Control (16)) ;
+fprintf ('        Only used if diagonal pivoting is attempted.\n') ;
+
+fprintf ('    Control (17): scaling option: %g ', Control (17)) ;
+if (Control (17) == 0)
+    fprintf ('(none)\n') ;
+elseif (Control (17) == 2)
+    fprintf ('(scale the matrix by\n') ;
+    fprintf ('        dividing each row by max. abs. value in each row)\n') ;
+else
+    fprintf ('(scale the matrix by\n') ;
+    fprintf ('        dividing each row by sum of abs. values in each row)\n') ;
+end
+
+fprintf ('    Control (18): frontal matrix allocation ratio: %g\n', Control (18)) ;
+fprintf ('    Control (19): drop tolerance: %g\n', Control (19)) ;
+fprintf ('    Control (20): AMD and COLAMD aggressive absorption: %g ', Control (20)) ;
+yes_no (Control (20)) ;
+
+% compile-time options:
+
+fprintf ('\n  The following options can only be changed at compile-time:\n') ;
+
+if (Control (9) == 1)
+    fprintf ('    Control (9): compiled to use the BLAS\n') ;
+else
+    fprintf ('    Control (9): compiled without the BLAS\n') ;
+    fprintf ('        (you will not get the best possible performance)\n') ;
+end
+
+if (Control (10) == 1)
+    fprintf ('    Control (10): compiled for MATLAB\n') ;
+elseif (Control (10) == 2)
+    fprintf ('    Control (10): compiled for MATLAB\n') ;
+    fprintf ('        Uses internal utMalloc, utFree, utRealloc, utPrintf\n') ;
+    fprintf ('        utDivideComplex, and utFdlibm_hypot routines.\n') ;
+else
+    fprintf ('    Control (10): not compiled for MATLAB\n') ;
+    fprintf ('        Uses ANSI C malloc, free, realloc, and printf\n') ;
+    fprintf ('        instead of mxMalloc, mxFree, mxRealloc, and mexPrintf.\n') ;
+    fprintf ('        Printing will be in terms of 0-based matrix indexing,\n') ;
+    fprintf ('        not 1-based as is expected in MATLAB.  Diary output may\n') ;
+    fprintf ('        not be properly recorded.\n') ;
+end
+
+if (Control (11) == 2)
+    fprintf ('    Control (11): uses POSIX times ( ) to get CPU time and wallclock time.\n') ;
+elseif (Control (11) == 1)
+    fprintf ('    Control (11): uses getrusage to get CPU time.\n') ;
+else
+    fprintf ('    Control (11): uses ANSI C clock to get CPU time.\n') ;
+    fprintf ('        The CPU time may wrap around, type "help cputime".\n') ;
+end
+
+if (Control (12) == 1)
+    fprintf ('    Control (12): compiled with debugging enabled\n') ;
+    fprintf ('        ###########################################\n') ;
+    fprintf ('        ### This will be exceedingly slow! ########\n') ;
+    fprintf ('        ###########################################\n') ;
+    if (Control (10) == 1)
+        fprintf ('        Uses mxAssert.\n') ;
+    elseif (Control (10) == 2)
+        fprintf ('        Uses utAssert.\n') ;
+    else
+        fprintf ('        Uses ANSI C assert instead of mxAssert.\n') ;
+    end
+else
+    fprintf ('    Control (12): compiled for normal operation (no debugging)\n') ;
+end
+
+%-------------------------------------------------------------------------------
+% Info:
+%-------------------------------------------------------------------------------
+
+if (nargin == 1)
+    return
+end
+
+status = Info (1) ;
+fprintf ('\nUMFPACK status:  Info (1): %d, ', status) ;
+
+if (status == 0)
+    fprintf ('OK\n') ;
+elseif (status == 1)
+    fprintf ('WARNING  matrix is singular\n') ;
+elseif (status == -1)
+    fprintf ('ERROR    out of memory\n') ;
+elseif (status == -3)
+    fprintf ('ERROR    numeric LU factorization is invalid\n') ;
+elseif (status == -4)
+    fprintf ('ERROR    symbolic LU factorization is invalid\n') ;
+elseif (status == -5)
+    fprintf ('ERROR    required argument is missing\n') ;
+elseif (status == -6)
+    fprintf ('ERROR    n <= 0\n') ;
+elseif (status <= -7 & status >= -12 | status == -14)
+    fprintf ('ERROR    matrix A is corrupted\n') ;
+elseif (status == -13)
+    fprintf ('ERROR    invalid system\n') ;
+elseif (status == -15)
+    fprintf ('ERROR    invalid permutation\n') ;
+elseif (status == -911)
+    fprintf ('ERROR    internal error!\n') ;
+    fprintf ('Please report this error to Tim Davis (davis@cise.ufl.edu)\n') ;
+else
+    fprintf ('ERROR    unrecognized error.  Info array corrupted\n') ;
+end
+
+fprintf ('    (a -1 means the entry has not been computed):\n') ;
+
+fprintf ('\n  Basic statistics:\n') ;
+fprintf ('    Info (2):  %d, # of rows of A\n', Info (2)) ;
+fprintf ('    Info (17): %d, # of columns of A\n', Info (17)) ;
+fprintf ('    Info (3): %d, nnz (A)\n', Info (3)) ;
+fprintf ('    Info (4): %d, Unit size, in bytes, for memory usage reported below\n', Info (4)) ;
+fprintf ('    Info (5): %d, size of int (in bytes)\n', Info (5)) ;
+fprintf ('    Info (6): %d, size of long (in bytes)\n', Info (6)) ;
+fprintf ('    Info (7): %d, size of pointer (in bytes)\n', Info (7)) ;
+fprintf ('    Info (8): %d, size of numerical entry (in bytes)\n', Info (8)) ;
+
+fprintf ('\n  Pivots with zero Markowitz cost removed to obtain submatrix S:\n') ;
+fprintf ('    Info (57): %d, # of pivots with one entry in pivot column\n', Info (57)) ;
+fprintf ('    Info (58): %d, # of pivots with one entry in pivot row\n', Info (58)) ;
+fprintf ('    Info (59): %d, # of rows/columns in submatrix S (if square)\n', Info (59)) ;
+fprintf ('    Info (60): %d ') ;
+if (Info (60) > 0)
+    fprintf ('submatrix S square and diagonal preserved\n') ;
+elseif (Info  (60) == 0)
+    fprintf ('submatrix S not square or diagonal not preserved\n') ;
+else
+    fprintf ('\n') ;
+end
+fprintf ('    Info (9):  %d, # of "dense" rows in S\n', Info (9)) ;
+fprintf ('    Info (10): %d, # of empty rows in S\n', Info (10)) ;
+fprintf ('    Info (11): %d, # of "dense" columns in S\n', Info (11)) ;
+fprintf ('    Info (12): %d, # of empty columns in S\n', Info (12)) ;
+fprintf ('    Info (34): %g, symmetry of pattern of S\n', Info (34)) ;
+fprintf ('    Info (35): %d, # of off-diagonal nonzeros in S+S''\n', Info (35)) ;
+fprintf ('    Info (36): %d, nnz (diag (S))\n', Info (36)) ;
+
+fprintf ('\n  2-by-2 pivoting to place large entries on diagonal:\n') ;
+fprintf ('    Info (52): %d, # of small diagonal entries of S\n', Info (52)) ;
+fprintf ('    Info (53): %d, # of unmatched small diagonal entries\n', Info (53)) ;
+fprintf ('    Info (54): %g, symmetry of P2*S\n', Info (54)) ;
+fprintf ('    Info (55): %d, # of off-diagonal entries in (P2*S)+(P2*S)''\n', Info (55)) ;
+fprintf ('    Info (56): %d, nnz (diag (P2*S))\n', Info (56)) ;
+
+fprintf ('\n  AMD results, for strict diagonal pivoting:\n') ;
+fprintf ('    Info (37): %d, est. nz in L and U\n', Info (37)) ;
+fprintf ('    Info (38): %g, est. flop count\n', Info (38)) ;
+fprintf ('    Info (39): %g, # of "dense" rows in S+S''\n', Info (39)) ;
+fprintf ('    Info (40): %g, est. max. nz in any column of L\n', Info (40)) ;
+
+fprintf ('\n  Final strategy selection, based on the analysis above:\n') ;
+prstrat ('    Info (19): %d, strategy used ', Info (19)) ;
+fprintf ('    Info (20): %d, ordering used ', Info (20)) ;
+if (Info (20) == 0)
+    fprintf ('(COLAMD on A)\n') ;
+elseif (Info (20) == 1)
+    fprintf ('(AMD on A+A'')\n') ;
+elseif (Info (20) == 2)
+    fprintf ('(provided by user)\n') ;
+else
+    fprintf ('(undefined ordering option)\n') ;
+end
+fprintf ('    Info (32): %d, Q fixed during numeric factorization: ', Info (32)) ;
+yes_no (Info (32)) ;
+fprintf ('    Info (33): %d, prefer diagonal pivoting: ', Info (33)) ;
+yes_no (Info (33)) ;
+
+fprintf ('\n  symbolic analysis time and memory usage:\n') ;
+fprintf ('    Info (13): %d, defragmentations during symbolic analysis\n', Info (13)) ;
+fprintf ('    Info (14): %d, memory used during symbolic analysis (Units)\n', Info (14)) ;
+fprintf ('    Info (15): %d, final size of symbolic factors (Units)\n', Info (15)) ;
+fprintf ('    Info (16): %.2f, symbolic analysis CPU time (seconds)\n', Info (16)) ;
+fprintf ('    Info (18): %.2f, symbolic analysis wall clock time (seconds)\n', Info (18)) ;
+
+fprintf ('\n  Estimates computed in the symbolic analysis:\n') ;
+fprintf ('    Info (21): %d, est. size of LU factors (Units)\n', Info (21)) ;
+fprintf ('    Info (22): %d, est. total peak memory usage (Units)\n', Info (22)) ;
+fprintf ('    Info (23): %d, est. factorization flop count\n', Info (23)) ;
+fprintf ('    Info (24): %d, est. nnz (L)\n', Info (24)) ;
+fprintf ('    Info (25): %d, est. nnz (U)\n', Info (25)) ;
+fprintf ('    Info (26): %d, est. initial size, variable-part of LU (Units)\n', Info (26)) ;
+fprintf ('    Info (27): %d, est. peak size, of variable-part of LU (Units)\n', Info (27)) ;
+fprintf ('    Info (28): %d, est. final size, of variable-part of LU (Units)\n', Info (28)) ;
+fprintf ('    Info (29): %d, est. max frontal matrix size (# of entries)\n', Info (29)) ;
+fprintf ('    Info (30): %d, est. max # of rows in frontal matrix\n', Info (30)) ;
+fprintf ('    Info (31): %d, est. max # of columns in frontal matrix\n', Info (31)) ;
+
+fprintf ('\n  Computed in the numeric factorization (estimates shown above):\n') ;
+fprintf ('    Info (41): %d, size of LU factors (Units)\n', Info (41)) ;
+fprintf ('    Info (42): %d, total peak memory usage (Units)\n', Info (42)) ;
+fprintf ('    Info (43): %d, factorization flop count\n', Info (43)) ;
+fprintf ('    Info (44): %d, nnz (L)\n', Info (44)) ;
+fprintf ('    Info (45): %d, nnz (U)\n', Info (45)) ;
+fprintf ('    Info (46): %d, initial size of variable-part of LU (Units)\n', Info (46)) ;
+fprintf ('    Info (47): %d, peak size of variable-part of LU (Units)\n', Info (47)) ;
+fprintf ('    Info (48): %d, final size of variable-part of LU (Units)\n', Info (48)) ;
+fprintf ('    Info (49): %d, max frontal matrix size (# of numerical entries)\n', Info (49)) ;
+fprintf ('    Info (50): %d, max # of rows in frontal matrix\n', Info (50)) ;
+fprintf ('    Info (51): %d, max # of columns in frontal matrix\n', Info (51)) ;
+
+fprintf ('\n  Computed in the numeric factorization (no estimates computed a priori):\n') ;
+fprintf ('    Info (61): %d, defragmentations during numeric factorization\n', Info (61)) ;
+fprintf ('    Info (62): %d, reallocations during numeric factorization\n', Info (62)) ;
+fprintf ('    Info (63): %d, costly reallocations during numeric factorization\n', Info (63)) ;
+fprintf ('    Info (64): %d, integer indices in compressed pattern of L and U\n', Info (64)) ;
+fprintf ('    Info (65): %d, numerical values stored in L and U\n', Info (65)) ;
+fprintf ('    Info (66): %.2f, numeric factorization CPU time (seconds)\n', Info (66)) ;
+fprintf ('    Info (76): %.2f, numeric factorization wall clock time (seconds)\n', Info (76)) ;
+if (Info (66) > 0.05 & Info (43) > 0)
+fprintf ('    mflops in numeric factorization phase: %.2f\n', 1e-6 * Info (43) / Info (66)) ;
+end
+fprintf ('    Info (67): %d, nnz (diag (U))\n', Info (67)) ;
+fprintf ('    Info (68): %g, reciprocal condition number estimate\n', Info (68)) ;
+fprintf ('    Info (69): %g, matrix was ', Info (69)) ;
+if (Info (69) == 0)
+    fprintf ('not scaled\n') ;
+elseif (Info (69) == 2)
+    fprintf ('scaled (row max)\n') ;
+else
+    fprintf ('scaled (row sum)\n') ;
+end
+fprintf ('    Info (70): %g, min. scale factor of rows of A\n', Info (70)) ;
+fprintf ('    Info (71): %g, max. scale factor of rows of A\n', Info (71)) ;
+fprintf ('    Info (72): %g, min. abs. on diagonal of U\n', Info (72)) ;
+fprintf ('    Info (73): %g, max. abs. on diagonal of U\n', Info (73)) ;
+fprintf ('    Info (74): %g, initial allocation parameter used\n', Info (74)) ;
+fprintf ('    Info (75): %g, # of forced updates due to frontal growth\n', Info (75)) ;
+fprintf ('    Info (77): %d, # of off-diaogonal pivots\n', Info (77)) ;
+fprintf ('    Info (78): %d, nnz (L), if no small entries dropped\n', Info (78)) ;
+fprintf ('    Info (79): %d, nnz (U), if no small entries dropped\n', Info (79)) ;
+fprintf ('    Info (80): %d, # of small entries dropped\n', Info (80)) ;
+
+fprintf ('\n  Computed in the solve step:\n') ;
+fprintf ('    Info (81): %d, iterative refinement steps taken\n', Info (81)) ;
+fprintf ('    Info (82): %d, iterative refinement steps attempted\n', Info (82)) ;
+fprintf ('    Info (83): %g, omega(1), sparse-backward error estimate\n', Info (83)) ;
+fprintf ('    Info (84): %g, omega(2), sparse-backward error estimate\n', Info (84)) ;
+fprintf ('    Info (85): %d, solve flop count\n', Info (85)) ;
+fprintf ('    Info (86): %.2f, solve CPU time (seconds)\n', Info (86)) ;
+fprintf ('    Info (87): %.2f, solve wall clock time (seconds)\n', Info (87)) ;
+
+fprintf ('\n    Info (88:90): unused\n\n') ;
+
+%-------------------------------------------------------------------------------
+
+function prstrat (fmt, strategy)
+fprintf (fmt, strategy) ;
+if (strategy == 1)
+    fprintf ('(unsymmetric)\n') ;
+    fprintf ('        Q = COLAMD (A), Q refined during numerical\n') ;
+    fprintf ('        factorization, and no attempt at diagonal pivoting.\n') ;
+elseif (strategy == 2)
+    fprintf ('(symmetric, with 2-by-2 pivoting)\n') ;
+    fprintf ('        P2 = row permutation to place large values on the diagonal\n') ;
+    fprintf ('        Q = AMD (P2*A+(P2*A)''), Q not refined during numeric factorization,\n') ;
+    fprintf ('        and diagonal pivoting attempted.\n') ;
+elseif (strategy == 3)
+    fprintf ('(symmetric)\n') ;
+    fprintf ('        Q = AMD (A+A''), Q not refined during numeric factorization,\n') ;
+    fprintf ('        and diagonal pivoting (P=Q'') attempted.\n') ;
+else
+    strategy = 0 ;
+    fprintf ('(auto)\n') ;
+end
+
+%-------------------------------------------------------------------------------
+
+function yes_no (s)
+if (s == 0)
+    fprintf ('(no)\n') ;
+else
+    fprintf ('(yes)\n') ;
+end
diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_simple.m b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_simple.m
new file mode 100644 (file)
index 0000000..829b671
--- /dev/null
@@ -0,0 +1,61 @@
+% umfpack_simple:  a simple demo of UMFPACK
+%
+% UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.
+% Davis.  All Rights Reserved.
+% 
+% UMFPACK License:
+% 
+%     Your use or distribution of UMFPACK or any modified version of
+%     UMFPACK implies that you agree to this License.
+% 
+%     THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
+%     EXPRESSED OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+% 
+%     Permission is hereby granted to use or copy this program, provided
+%     that the Copyright, this License, and the Availability of the original
+%     version is retained on all copies.  User documentation of any code that
+%     uses UMFPACK or any modified version of UMFPACK code must cite the
+%     Copyright, this License, the Availability note, and "Used by permission."
+%     Permission to modify the code and to distribute modified code is granted,
+%     provided the Copyright, this License, and the Availability note are
+%     retained, and a notice that the code was modified is included.  This
+%     software was developed with support from the National Science Foundation,
+%     and is provided to you free of charge.
+% 
+% Availability: http://www.cise.ufl.edu/research/sparse/umfpack
+%
+% See also: umfpack, umfpack_details
+
+help umfpack_simple
+i = input ('Hit enter to agree to the above License: ', 's') ;
+if (~isempty (i))
+    error ('terminating') ;
+end
+
+format short
+
+A = [
+ 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
+]
+
+A = sparse (A) ;
+
+b = [8 45 -3 3 19]'
+
+fprintf ('Solution to Ax=b via UMFPACK:\n') ;
+fprintf ('x1 = umfpack (A, ''\\'', b)\n') ;
+
+x1 = umfpack (A, '\', b)
+
+fprintf ('Solution to Ax=b via MATLAB:\n') ;
+fprintf ('x2 = A\\b\n') ;
+
+x2 = A\b
+
+fprintf ('norm (x1-x2) should be small: %g\n', norm (x1-x2)) ;
+
+fprintf ('Type ''umfpack_demo'' for a full demo of UMFPACK\n') ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_simple.m.out b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_simple.m.out
new file mode 100644 (file)
index 0000000..6c01914
--- /dev/null
@@ -0,0 +1,74 @@
+>> umfpack_simple
+
+  umfpack_simple:  a simple demo of UMFPACK
+  UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.
+  Davis.  All Rights Reserved.
+  
+  UMFPACK License:
+  
+      Your use or distribution of UMFPACK or any modified version of
+      UMFPACK implies that you agree to this License.
+  
+      THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
+      EXPRESSED OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+  
+      Permission is hereby granted to use or copy this program, provided
+      that the Copyright, this License, and the Availability of the original
+      version is retained on all copies.  User documentation of any code that
+      uses UMFPACK or any modified version of UMFPACK code must cite the
+      Copyright, this License, the Availability note, and "Used by permission."
+      Permission to modify the code and to distribute modified code is granted,
+      provided the Copyright, this License, and the Availability note are
+      retained, and a notice that the code was modified is included.  This
+      software was developed with support from the National Science Foundation,
+      and is provided to you free of charge.
+  
+  Availability: http://www.cise.ufl.edu/research/sparse/umfpack
+  See also: umfpack, umfpack_details
+
+Hit enter to agree to the above License: 
+
+A =
+
+     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
+
+
+b =
+
+     8
+    45
+    -3
+     3
+    19
+
+Solution to Ax=b via UMFPACK:
+x1 = umfpack (A, '\', b)
+
+x1 =
+
+    1.0000
+    2.0000
+    3.0000
+    4.0000
+    5.0000
+
+Solution to Ax=b via MATLAB:
+x2 = A\b
+
+x2 =
+
+    1.0000
+    2.0000
+    3.0000
+    4.0000
+    5.0000
+
+norm (x1-x2) should be small: 1.28037e-15
+Type 'umfpack_demo' for a full demo of UMFPACK
+>> diary off
diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_solve.m b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_solve.m
new file mode 100644 (file)
index 0000000..1a988c5
--- /dev/null
@@ -0,0 +1,96 @@
+function x = umfpack_solve (arg1, op, arg2, Control)
+% UMFPACK_SOLVE
+%
+% x = umfpack_solve (A, '\', b, Control)
+% x = umfpack_solve (b, '/', A, Control)
+%
+% Computes x = A\b, or b/A, where A is square.  Uses UMFPACK if A is sparse.
+% The Control argument is optional.
+%
+% See also umfpack, umfpack_make, umfpack_details, umfpack_report,
+% and umfpack_simple.
+
+% UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.
+% Davis.  All Rights Reserved.  Type umfpack_details for License.
+
+%-------------------------------------------------------------------------------
+% check inputs and get default control parameters
+%-------------------------------------------------------------------------------
+
+if (op == '\')
+    A = arg1 ;
+    b = arg2 ;
+elseif (op == '/')
+    A = arg2 ;
+    b = arg1 ;
+else
+    help umfack_solve
+    error ('umfpack_solve:  unrecognized operator') ;
+end
+
+[m n] = size (A) ;
+if (m ~= n)
+    help umfpack_solve
+    error ('umfpack_solve:  A must be square') ;
+end
+
+[m1 n1] = size (b) ;
+if ((op == '\' & n ~= m1) | (op == '/' & n1 ~= m))
+    help umfpack_solve
+    error ('umfpack_solve:  b has the wrong dimensions') ;
+end
+
+if (nargin < 4)
+    Control = umfpack ;
+end
+
+%-------------------------------------------------------------------------------
+% solve the system
+%-------------------------------------------------------------------------------
+
+if (op == '\')
+
+    if (~issparse (A))
+
+       % A is not sparse, so just use MATLAB
+       x = A\b ;
+
+    elseif (n1 == 1 & ~issparse (b))
+
+       % the UMFPACK '\' requires b to be a dense column vector
+       x = umfpack (A, '\', b, Control) ;
+
+    else
+
+       % factorize with UMFPACK and do the forward/back solves in MATLAB 
+       [L, U, P, Q, R] = umfpack (A, Control) ;
+       x = Q * (U \ (L \ (P * (R \ b)))) ;
+
+    end
+
+else
+
+    if (~issparse (A))
+
+       % A is not sparse, so just use MATLAB
+       x = b/A ;
+
+    elseif (m1 == 1 & ~issparse (b))
+
+       % the UMFPACK '\' requires b to be a dense column vector
+       x = umfpack (b, '/', A, Control) ;
+
+    else
+
+       % factorize with UMFPACK and do the forward/back solves in MATLAB
+       % this mimics the behavior of x = b/A, except for the row scaling
+       [L, U, P, Q, R] = umfpack (A.', Control) ;
+       x = (Q * (U \ (L \ (P * (R \ (b.')))))).' ;
+
+       % an alternative method:
+       % [L, U, P, Q, r] = umfpack (A, Control) ;
+       % x = (R \ (P' * (L.' \ (U.' \ (Q' * b.'))))).' ;
+
+    end
+
+end
diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpackmex.c b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpackmex.c
new file mode 100644 (file)
index 0000000..8e64a7e
--- /dev/null
@@ -0,0 +1,1284 @@
+/* ========================================================================== */
+/* === UMFPACK mexFunction ================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+/* Minor revision, Aug 13, 2003 (version 4.1.1).  Removed call to spparms.    */
+/* -------------------------------------------------------------------------- */
+
+/*
+    MATLAB interface for umfpack.
+
+    Factor or solve a sparse linear system, returning either the solution
+    x to Ax=b or A'x'=b', or the factorization LU=P(R\A)Q or LU=PAQ.  A must be
+    sparse, with nonzero dimensions, but it may be complex, singular, and/or
+    rectangular.  b must be a dense n-by-1 vector (real or complex).
+    L is unit lower triangular, U is upper triangular, and R is diagonal.
+    P and Q are permutation matrices (permutations of an identity matrix).
+
+    This has changed since v4.0.  The outputs P and Q are returned as
+    permutation matrices instead of permutation vectors, and the row scale
+    factor r is also returned.  v4.0 did not scale the matrix.
+
+    The matrix A is scaled, by default.  Each row i is divided by r (i), where
+    r (i) is the sum of the absolute values of the entries in that row.  The
+    scaled matrix has an infinity norm of 1.  The scale factors r (i) are
+    returned in a diagonal sparse matrix.  If the factorization is:
+
+       [L, U, P, Q, R] = umfpack (A) ;
+
+    then the factorization is
+
+       L*U = P * (R \ A) * Q
+
+    This is safer than returning a matrix R such that L*U = P*R*A*Q, because
+    it avoids the division by small entries.  If r(i) is subnormal, multiplying
+    by 1/r(i) would result in an IEEE Infinity, but dividing by r(i) is safe.
+
+    The factorization
+
+       [L, U, P, Q] = umfpack (A) ;
+
+    returns LU factors such that L*U = P*A*Q, with no scaling.
+
+    See umfpack.m and umfpack.h for details.
+
+    Note that this mexFunction accesses only the user-callable UMFPACK routines.
+    Thus, is also provides another example of how user C code can access
+    UMFPACK.
+
+    If NO_TRANSPOSE_FORWARD_SLASH is not defined at compile time, then the
+    forward slash (/) operator acts almost like x = b/A in MATLAB 6.1.  It is
+    solved by factorizing the array transpose, and then x = (A.'\b.').' is
+    solved.  This is the default behavior (for historical reasons), since
+    factorizing A can behave perform much differently than factorizing its
+    transpose.
+
+    If NO_TRANSPOSE_FORWARD_SLASH is defined at compile time, then the forward
+    slash operator does not act like x=b/A in MATLAB 6.1.  It is solved by
+    factorizing A, and then solving via the transposed L and U matrices.
+    The solution is still x = (A.'\b.').', except that A is factorized instead
+    of A.'.
+*/
+
+#include "umfpack.h"
+#include "mex.h"
+#include "matrix.h"
+#include <string.h>
+#include <math.h>
+#include <float.h>
+
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#define STRING_MATCH(s1,s2) (strcmp ((s1), (s2)) == 0)
+#ifndef TRUE
+#define TRUE (1)
+#endif
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+/* ========================================================================== */
+/* === error ================================================================ */
+/* ========================================================================== */
+
+/* Return an error message */
+
+static void error
+(
+    char *s,
+    int A_is_complex,
+    int nargout,
+    mxArray *pargout [ ],
+    double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO],
+    int status,
+    int do_info
+)
+{
+    int i ;
+    double *OutInfo ;
+    if (A_is_complex)
+    {
+       umfpack_zi_report_status (Control, status) ;
+       umfpack_zi_report_info (Control, Info) ;
+    }
+    else
+    {
+       umfpack_di_report_status (Control, status) ;
+       umfpack_di_report_info (Control, Info) ;
+    }
+    if (do_info > 0)
+    {
+       /* return Info */
+       pargout [do_info] = mxCreateDoubleMatrix (1, UMFPACK_INFO, mxREAL) ;
+       OutInfo = mxGetPr (pargout [do_info]) ;
+       for (i = 0 ; i < UMFPACK_INFO ; i++)
+       {
+           OutInfo [i] = Info [i] ;
+       }
+    }
+    mexErrMsgTxt (s) ;
+}
+
+
+/* ========================================================================== */
+/* === UMFPACK ============================================================== */
+/* ========================================================================== */
+
+void mexFunction
+(
+    int nargout,               /* number of outputs */
+    mxArray *pargout [ ],      /* output arguments */
+    int nargin,                        /* number of inputs */
+    const mxArray *pargin [ ]  /* input arguments */
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    void *Symbolic, *Numeric ;
+    int *Lp, *Li, *Up, *Ui, *Ap, *Ai, *P, *Q, do_solve, lnz, unz, nn, i,
+       transpose, size, do_info, do_numeric, *Front_npivcol, op, k, *Rp, *Ri,
+       *Front_parent, *Chain_start, *Chain_maxrows, *Chain_maxcols, nz, status,
+       nfronts, nchains, *Ltp, *Ltj, *Qinit, print_level, status2, no_scale,
+       *Front_1strow, *Front_leftmostdesc, n_row, n_col, n_inner, sys,
+       ignore1, ignore2, ignore3, A_is_complex, B_is_complex, X_is_complex,
+       *Pp, *Pi, *Qp, *Qi, do_recip ;
+    double *Lx, *Lz, *Ux, *Uz, *Ax, *Az, *Bx, *Bz, *Xx, *Xz, *User_Control,
+       *p, *q, Info [UMFPACK_INFO], Control [UMFPACK_CONTROL], *OutInfo,
+       *p1, *p2, *p3, *p4, *Ltx, *Ltz, *Rs, *Px, *Qx ;
+    mxArray *Amatrix, *Bmatrix, *User_Control_matrix, *User_Qinit ;
+    char *operator, *operation ;
+    mxComplexity Atype, Xtype ;
+    char warning [200] ;
+
+#ifndef NO_TRANSPOSE_FORWARD_SLASH
+    int *Cp, *Ci ;
+    double *Cx, *Cz ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs A, b, and the operation to perform */
+    /* ---------------------------------------------------------------------- */
+
+    User_Control_matrix = (mxArray *) NULL ;
+    User_Qinit = (mxArray *) NULL ;
+
+    do_info = 0 ;
+    do_solve = FALSE ;
+    do_numeric = TRUE ;
+    transpose = FALSE ;
+    no_scale = FALSE ;
+
+    /* find the operator */
+    op = 0 ;
+    for (i = 0 ; i < nargin ; i++)
+    {
+       if (mxIsChar (pargin [i]))
+       {
+           op = i ;
+           break ;
+       }
+    }
+
+    if (op > 0)
+    {
+       operator = mxArrayToString (pargin [op]) ;
+
+       if (STRING_MATCH (operator, "\\"))
+       {
+
+           /* -------------------------------------------------------------- */
+           /* matrix left divide, x = A\b */
+           /* -------------------------------------------------------------- */
+
+           /*
+               [x, Info] = umfpack (A, '\', b) ;
+               [x, Info] = umfpack (A, '\', b, Control) ;
+               [x, Info] = umfpack (A, Qinit, '\', b, Control) ;
+               [x, Info] = umfpack (A, Qinit, '\', b) ;
+           */
+
+           operation = "x = A\\b" ;
+           do_solve = TRUE ;
+           Amatrix = (mxArray *) pargin [0] ;
+           Bmatrix = (mxArray *) pargin [op+1] ;
+
+           if (nargout == 2)
+           {
+               do_info = 1 ;
+           }
+           if (op == 2)
+           {
+               User_Qinit = (mxArray *) pargin [1] ;
+           }
+           if ((op == 1 && nargin == 4) || (op == 2 && nargin == 5))
+           {
+               User_Control_matrix = (mxArray *) pargin [nargin-1] ;
+           }
+           if (nargin < 3 || nargin > 5 || nargout > 2)
+           {
+               mexErrMsgTxt ("wrong number of arguments") ;
+           }
+
+       }
+       else if (STRING_MATCH (operator, "/"))
+       {
+
+           /* -------------------------------------------------------------- */
+           /* matrix right divide, x = b/A */
+           /* -------------------------------------------------------------- */
+
+           /*
+               [x, Info] = umfpack (b, '/', A) ;
+               [x, Info] = umfpack (b, '/', A, Control) ;
+               [x, Info] = umfpack (b, '/', A, Qinit) ;
+               [x, Info] = umfpack (b, '/', A, Qinit, Control) ;
+           */
+
+           operation = "x = b/A" ;
+           do_solve = TRUE ;
+           transpose = TRUE ;
+           Amatrix = (mxArray *) pargin [2] ;
+           Bmatrix = (mxArray *) pargin [0] ;
+
+           if (nargout == 2)
+           {
+               do_info = 1 ;
+           }
+           if (nargin == 5)
+           {
+               User_Qinit = (mxArray *) pargin [3] ;
+               User_Control_matrix = (mxArray *) pargin [4] ;
+           }
+           else if (nargin == 4)
+           {
+               /* Control is k-by-1 where k > 1, Qinit is 1-by-n */
+               if (mxGetM (pargin [3]) == 1)
+               {
+                   User_Qinit = (mxArray *) pargin [3] ;
+               }
+               else
+               {
+                   User_Control_matrix = (mxArray *) pargin [3] ;
+               }
+           }
+           else if (nargin < 3 || nargin > 5 || nargout > 2)
+           {
+               mexErrMsgTxt ("wrong number of arguments") ;
+           }
+
+       }
+       else if (STRING_MATCH (operator, "symbolic"))
+       {
+
+           /* -------------------------------------------------------------- */
+           /* symbolic factorization only */
+           /* -------------------------------------------------------------- */
+
+           /*
+           [P Q Fr Ch Info] = umfpack (A, 'symbolic') ;
+           [P Q Fr Ch Info] = umfpack (A, 'symbolic', Control) ;
+           [P Q Fr Ch Info] = umfpack (A, Qinit, 'symbolic') ;
+           [P Q Fr Ch Info] = umfpack (A, Qinit, 'symbolic', Control) ;
+           */
+
+           operation = "symbolic factorization" ;
+           do_numeric = FALSE ;
+           Amatrix = (mxArray *) pargin [0] ;
+
+           if (nargout == 5)
+           {
+               do_info = 4 ;
+           }
+           if (op == 2)
+           {
+               User_Qinit = (mxArray *) pargin [1] ;
+           }
+           if ((op == 1 && nargin == 3) || (op == 2 && nargin == 4))
+           {
+               User_Control_matrix = (mxArray *) pargin [nargin-1] ;
+           }
+           if (nargin < 2 || nargin > 4 || nargout > 5 || nargout < 4)
+           {
+               mexErrMsgTxt ("wrong number of arguments") ;
+           }
+
+       }
+       else
+       {
+           mexErrMsgTxt ("operator must be '/', '\\', or 'symbolic'") ;
+       }
+       mxFree (operator) ;
+
+    }
+    else if (nargin > 0)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* LU factorization */
+       /* ------------------------------------------------------------------ */
+
+       /*
+           with scaling:
+           [L, U, P, Q, R, Info] = umfpack (A) ;
+           [L, U, P, Q, R, Info] = umfpack (A, Qinit) ;
+
+           scaling determined by Control settings:
+           [L, U, P, Q, R, Info] = umfpack (A, Control) ;
+           [L, U, P, Q, R, Info] = umfpack (A, Qinit, Control) ;
+
+           with no scaling:
+           [L, U, P, Q] = umfpack (A) ;
+           [L, U, P, Q] = umfpack (A, Control) ;
+           [L, U, P, Q] = umfpack (A, Qinit) ;
+           [L, U, P, Q] = umfpack (A, Qinit, Control) ;
+       */
+
+       operation = "numeric factorization" ;
+       Amatrix = (mxArray *) pargin [0] ;
+
+       no_scale = nargout <= 4 ;
+
+       if (nargout == 6)
+       {
+           do_info = 5 ;
+       }
+       if (nargin == 3)
+       {
+           User_Qinit = (mxArray *) pargin [1] ;
+           User_Control_matrix = (mxArray *) pargin [2] ;
+       }
+       else if (nargin == 2)
+       {
+           /* Control is k-by-1 where k > 1, Qinit is 1-by-n */
+           if (mxGetM (pargin [1]) == 1)
+           {
+               User_Qinit = (mxArray *) pargin [1] ;
+           }
+           else
+           {
+               User_Control_matrix = (mxArray *) pargin [1] ;
+           }
+       }
+       else if (nargin > 3 || nargout > 6 || nargout < 4)
+       {
+           mexErrMsgTxt ("wrong number of arguments") ;
+       }
+
+    }
+    else
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* return default control settings */
+       /* ------------------------------------------------------------------ */
+
+       /*
+           Control = umfpack ;
+           umfpack ;
+       */
+
+       if (nargout > 1)
+       {
+           mexErrMsgTxt ("wrong number of arguments") ;
+       }
+
+       pargout [0] = mxCreateDoubleMatrix (UMFPACK_CONTROL, 1, mxREAL) ;
+       User_Control = mxGetPr (pargout [0]) ;
+       umfpack_di_defaults (User_Control) ;
+
+       return ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    if (mxGetNumberOfDimensions (Amatrix) != 2)
+    {
+       mexErrMsgTxt ("input matrix A must be 2-dimensional") ;
+    }
+    n_row = mxGetM (Amatrix) ;
+    n_col = mxGetN (Amatrix) ;
+    nn = MAX (n_row, n_col) ;
+    n_inner = MIN (n_row, n_col) ;
+    if (do_solve && n_row != n_col)
+    {
+       mexErrMsgTxt ("input matrix A must square for '\\' or '/'") ;
+    }
+    if (!mxIsSparse (Amatrix))
+    {
+       mexErrMsgTxt ("input matrix A must be sparse") ;
+    }
+    if (n_row == 0 || n_col == 0)
+    {
+       mexErrMsgTxt ("input matrix A cannot have zero rows or zero columns") ;
+    }
+
+    /* The real/complex status of A determines which version to use, */
+    /* (umfpack_di_* or umfpack_zi_*). */
+    A_is_complex = mxIsComplex (Amatrix) ;
+    Atype = A_is_complex ? mxCOMPLEX : mxREAL ;
+    Ap = mxGetJc (Amatrix) ;
+    Ai = mxGetIr (Amatrix) ;
+    Ax = mxGetPr (Amatrix) ;
+    Az = mxGetPi (Amatrix) ;
+
+    if (do_solve)
+    {
+
+       if (n_row != n_col)
+       {
+           mexErrMsgTxt ("A must be square for \\ or /") ;
+       }
+       if (transpose)
+       {
+           if (mxGetM (Bmatrix) != 1 || mxGetN (Bmatrix) != nn)
+           {
+               mexErrMsgTxt ("b has the wrong dimensions") ;
+           }
+       }
+       else
+       {
+           if (mxGetM (Bmatrix) != nn || mxGetN (Bmatrix) != 1)
+           {
+               mexErrMsgTxt ("b has the wrong dimensions") ;
+           }
+       }
+       if (mxGetNumberOfDimensions (Bmatrix) != 2)
+       {
+           mexErrMsgTxt ("input matrix b must be 2-dimensional") ;
+       }
+       if (mxIsSparse (Bmatrix))
+       {
+           mexErrMsgTxt ("input matrix b cannot be sparse") ;
+       }
+       if (mxGetClassID (Bmatrix) != mxDOUBLE_CLASS)
+       {
+           mexErrMsgTxt ("input matrix b must double precision matrix") ;
+       }
+
+       B_is_complex = mxIsComplex (Bmatrix) ;
+       Bx = mxGetPr (Bmatrix) ;
+       Bz = mxGetPi (Bmatrix) ;
+
+       X_is_complex = A_is_complex || B_is_complex ;
+       Xtype = X_is_complex ? mxCOMPLEX : mxREAL ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* set the Control parameters */
+    /* ---------------------------------------------------------------------- */
+
+    if (A_is_complex)
+    {
+       umfpack_zi_defaults (Control) ;
+    }
+    else
+    {
+       umfpack_di_defaults (Control) ;
+    }
+    if (User_Control_matrix)
+    {
+       if (mxGetClassID (User_Control_matrix) != mxDOUBLE_CLASS ||
+           mxIsSparse (User_Control_matrix))
+       {
+           mexErrMsgTxt ("Control must be a dense real matrix") ;
+       }
+       size = UMFPACK_CONTROL ;
+       size = MIN (size, mxGetNumberOfElements (User_Control_matrix)) ;
+       User_Control = mxGetPr (User_Control_matrix) ;
+       for (i = 0 ; i < size ; i++)
+       {
+           Control [i] = User_Control [i] ;
+       }
+    }
+
+    if (no_scale)
+    {
+       /* turn off scaling for [L, U, P, Q] = umfpack (A) ;
+        * ignoring the input value of Control (24) for the usage
+        * [L, U, P, Q] = umfpack (A, Control) ; */
+       Control [UMFPACK_SCALE] = UMFPACK_SCALE_NONE ;
+    }
+
+    if (mxIsNaN (Control [UMFPACK_PRL]))
+    {
+       print_level = UMFPACK_DEFAULT_PRL ;
+    }
+    else
+    {
+       print_level = (int) Control [UMFPACK_PRL] ;
+    }
+
+    Control [UMFPACK_PRL] = print_level ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get Qinit, if present */
+    /* ---------------------------------------------------------------------- */
+
+    if (User_Qinit)
+    {
+       if (mxGetM (User_Qinit) != 1 || mxGetN (User_Qinit) != n_col)
+       {
+           mexErrMsgTxt ("Qinit must be 1-by-n_col") ;
+       }
+       if (mxGetNumberOfDimensions (User_Qinit) != 2)
+       {
+           mexErrMsgTxt ("input Qinit must be 2-dimensional") ;
+       }
+       if (mxIsComplex (User_Qinit))
+       {
+           mexErrMsgTxt ("input Qinit must not be complex") ;
+       }
+       if (mxGetClassID (User_Qinit) != mxDOUBLE_CLASS)
+       {
+           mexErrMsgTxt ("input Qinit must be a double matrix") ;
+       }
+       if (mxIsSparse (User_Qinit))
+       {
+           mexErrMsgTxt ("input Qinit must be dense") ;
+       }
+       Qinit = (int *) mxMalloc (n_col * sizeof (int)) ;
+       p = mxGetPr (User_Qinit) ;
+       for (k = 0 ; k < n_col ; k++)
+       {
+           /* convert from 1-based to 0-based indexing */
+           Qinit [k] = ((int) (p [k])) - 1 ;
+       }
+
+    }
+    else
+    {
+       /* umfpack_*_qsymbolic will call colamd to get Qinit. This is the */
+       /* same as calling umfpack_*_symbolic with Qinit set to NULL*/
+       Qinit = (int *) NULL ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* report the inputs A and Qinit */
+    /* ---------------------------------------------------------------------- */
+
+    if (print_level >= 2)
+    {
+       /* print the operation */
+       mexPrintf ("\numfpack: %s\n", operation) ;
+    }
+
+    if (A_is_complex)
+    {
+       umfpack_zi_report_control (Control) ;
+       if (print_level >= 3) mexPrintf ("\nA: ") ;
+       (void) umfpack_zi_report_matrix (n_row, n_col, Ap, Ai, Ax, Az,
+           1, Control) ;
+       if (Qinit)
+       {
+           if (print_level >= 3) mexPrintf ("\nQinit: ") ;
+           (void) umfpack_zi_report_perm (n_col, Qinit, Control) ;
+       }
+    }
+    else
+    {
+       umfpack_di_report_control (Control) ;
+       if (print_level >= 3) mexPrintf ("\nA: ") ;
+       (void) umfpack_di_report_matrix (n_row, n_col, Ap, Ai, Ax,
+           1, Control) ;
+       if (Qinit)
+       {
+           if (print_level >= 3) mexPrintf ("\nQinit: ") ;
+           (void) umfpack_di_report_perm (n_col, Qinit, Control) ;
+       }
+    }
+
+#ifndef NO_TRANSPOSE_FORWARD_SLASH
+    /* ---------------------------------------------------------------------- */
+    /* create the array transpose for x = b/A */
+    /* ---------------------------------------------------------------------- */
+
+    if (transpose)
+    {
+       /* note that in this case A will be square (nn = n_row = n_col) */
+       /* x = (A.'\b.').' will be computed */
+
+       /* make sure Ci and Cx exist, avoid malloc of zero-sized arrays. */
+       nz = MAX (Ap [nn], 1) ;
+
+       Cp = (int *) mxMalloc ((nn+1) * sizeof (int)) ;
+       Ci = (int *) mxMalloc (nz * sizeof (int)) ;
+       Cx = (double *) mxMalloc (nz * sizeof (double)) ;
+       if (A_is_complex)
+       {
+           Cz = (double *) mxMalloc (nz * sizeof (double)) ;
+           status = umfpack_zi_transpose (nn, nn, Ap, Ai, Ax, Az,
+               (int *) NULL, (int *) NULL, Cp, Ci, Cx, Cz, FALSE) ;
+       }
+       else
+       {
+           status = umfpack_di_transpose (nn, nn, Ap, Ai, Ax,
+               (int *) NULL, (int *) NULL, Cp, Ci, Cx) ;
+       }
+
+       if (status != UMFPACK_OK)
+       {
+           error ("transpose of A failed", A_is_complex, nargout, pargout,
+               Control, Info, status, do_info);
+           return ;
+       }
+
+       /* modify pointers so that C will be factorized and solved, not A */
+       Ap = Cp ;
+       Ai = Ci ;
+       Ax = Cx ;
+       if (A_is_complex)
+       {
+           Az = Cz ;
+       }
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* perform the symbolic factorization */
+    /* ---------------------------------------------------------------------- */
+
+    if (A_is_complex)
+    {
+       status = umfpack_zi_qsymbolic (n_row, n_col, Ap, Ai, Ax, Az,
+           Qinit, &Symbolic, Control, Info) ;
+    }
+    else
+    {
+       status = umfpack_di_qsymbolic (n_row, n_col, Ap, Ai, Ax,
+           Qinit, &Symbolic, Control, Info) ;
+    }
+
+    if (Qinit)
+    {
+       mxFree (Qinit) ;
+    }
+
+    if (status < 0)
+    {
+       error ("symbolic factorization failed", A_is_complex, nargout, pargout,
+           Control, Info, status, do_info) ;
+       return ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* report the Symbolic object */
+    /* ---------------------------------------------------------------------- */
+
+    if (A_is_complex)
+    {
+       (void) umfpack_zi_report_symbolic (Symbolic, Control) ;
+    }
+    else
+    {
+       (void) umfpack_di_report_symbolic (Symbolic, Control) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* perform numeric factorization, or just return symbolic factorization */
+    /* ---------------------------------------------------------------------- */
+
+    if (do_numeric)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* perform the numeric factorization */
+       /* ------------------------------------------------------------------ */
+
+       if (A_is_complex)
+       {
+           status = umfpack_zi_numeric (Ap, Ai, Ax, Az, Symbolic, &Numeric,
+               Control, Info) ;
+       }
+       else
+       {
+           status = umfpack_di_numeric (Ap, Ai, Ax, Symbolic, &Numeric,
+               Control, Info) ;
+       }
+
+       /* ------------------------------------------------------------------ */
+       /* free the symbolic factorization */
+       /* ------------------------------------------------------------------ */
+
+       if (A_is_complex)
+       {
+           umfpack_zi_free_symbolic (&Symbolic) ;
+       }
+       else
+       {
+           umfpack_di_free_symbolic (&Symbolic) ;
+       }
+
+       /* ------------------------------------------------------------------ */
+       /* report the Numeric object */
+       /* ------------------------------------------------------------------ */
+
+       if (status < 0)
+       {
+           error ("numeric factorization failed", A_is_complex, nargout,
+               pargout, Control, Info, status, do_info);
+           return ;
+       }
+
+       if (A_is_complex)
+       {
+           (void) umfpack_zi_report_numeric (Numeric, Control) ;
+       }
+       else
+       {
+           (void) umfpack_di_report_numeric (Numeric, Control) ;
+       }
+
+       /* ------------------------------------------------------------------ */
+       /* return the solution or the factorization */
+       /* ------------------------------------------------------------------ */
+
+       if (do_solve)
+       {
+           /* -------------------------------------------------------------- */
+           /* solve Ax=b or A'x'=b', and return just the solution x */
+           /* -------------------------------------------------------------- */
+
+#ifndef NO_TRANSPOSE_FORWARD_SLASH
+           if (transpose)
+           {
+               /* A.'x.'=b.' gives the same x=b/A as solving A'x'=b' */
+               /* since C=A.' was factorized, solve with sys = UMFPACK_A */
+               /* since x and b are vectors, x.' and b.' are implicit */
+               pargout [0] = mxCreateDoubleMatrix (1, nn, Xtype) ;
+           }
+           else
+           {
+               pargout [0] = mxCreateDoubleMatrix (nn, 1, Xtype) ;
+           }
+           sys = UMFPACK_A ;
+#else
+           if (transpose)
+           {
+               /* If A is real, A'x=b is the same as A.'x=b. */
+               /* x and b are vectors, so x and b are the same as x' and b'. */
+               /* If A is complex, then A.'x.'=b.' gives the same solution x */
+               /* as the complex conjugate transpose.  If we used the A'x=b */
+               /* option in umfpack_*_solve, we would have to form b' on */
+               /* input and x' on output (negating the imaginary part). */
+               /* We can save this work by just using the A.'x=b option in */
+               /* umfpack_*_solve.  Then, forming x.' and b.' is implicit, */
+               /* since x and b are just vectors anyway. */
+               /* In both cases, the system to solve is A.'x=b */
+               pargout [0] = mxCreateDoubleMatrix (1, nn, Xtype) ;
+               sys = UMFPACK_Aat ;
+           }
+           else
+           {
+               pargout [0] = mxCreateDoubleMatrix (nn, 1, Xtype) ;
+               sys = UMFPACK_A ;
+           }
+#endif
+
+           /* -------------------------------------------------------------- */
+           /* print the right-hand-side, B */
+           /* -------------------------------------------------------------- */
+
+           if (print_level >= 3) mexPrintf ("\nright-hand side, b: ") ;
+           if (B_is_complex)
+           {
+               (void) umfpack_zi_report_vector (nn, Bx, Bz, Control) ;
+           }
+           else
+           {
+               (void) umfpack_di_report_vector (nn, Bx, Control) ;
+           }
+
+           /* -------------------------------------------------------------- */
+           /* solve the system */
+           /* -------------------------------------------------------------- */
+
+           Xx = mxGetPr (pargout [0]) ;
+           Xz = mxGetPi (pargout [0]) ;
+           status2 = UMFPACK_OK ;
+
+           if (A_is_complex)
+           {
+               if (!B_is_complex)
+               {
+                   /* umfpack_zi_solve expects a complex B */
+                   Bz = (double *) mxCalloc (nn, sizeof (double)) ;
+               }
+               status = umfpack_zi_solve (sys, Ap, Ai, Ax, Az, Xx, Xz, Bx, Bz,
+                   Numeric, Control, Info) ;
+               if (!B_is_complex)
+               {
+                   mxFree (Bz) ;
+               }
+           }
+           else
+           {
+               if (B_is_complex)
+               {
+                   /* Ax=b when b is complex and A is sparse can be split */
+                   /* into two systems, A*xr=br and A*xi=bi, where r denotes */
+                   /* the real part and i the imaginary part of x and b. */
+                   status2 = umfpack_di_solve (sys, Ap, Ai, Ax, Xz, Bz,
+                   Numeric, Control, Info) ;
+               }
+               status = umfpack_di_solve (sys, Ap, Ai, Ax, Xx, Bx,
+                   Numeric, Control, Info) ;
+           }
+
+#ifndef NO_TRANSPOSE_FORWARD_SLASH
+           /* -------------------------------------------------------------- */
+           /* free the transposed matrix C */
+           /* -------------------------------------------------------------- */
+
+           if (transpose)
+           {
+               mxFree (Cp) ;
+               mxFree (Ci) ;
+               mxFree (Cx) ;
+               if (A_is_complex)
+               {
+                   mxFree (Cz) ;
+               }
+           }
+#endif
+
+           /* -------------------------------------------------------------- */
+           /* free the Numeric object */
+           /* -------------------------------------------------------------- */
+
+           if (A_is_complex)
+           {
+               umfpack_zi_free_numeric (&Numeric) ;
+           }
+           else
+           {
+               umfpack_di_free_numeric (&Numeric) ;
+           }
+
+           /* -------------------------------------------------------------- */
+           /* check error status */
+           /* -------------------------------------------------------------- */
+
+           if (status < 0 || status2 < 0)
+           {
+               mxDestroyArray (pargout [0]) ;
+               error ("solve failed", A_is_complex, nargout, pargout, Control,
+                       Info, status, do_info) ;
+               return ;
+           }
+
+           /* -------------------------------------------------------------- */
+           /* print the solution, X */
+           /* -------------------------------------------------------------- */
+
+           if (print_level >= 3) mexPrintf ("\nsolution, x: ") ;
+           if (X_is_complex)
+           {
+               (void) umfpack_zi_report_vector (nn, Xx, Xz, Control) ;
+           }
+           else
+           {
+               (void) umfpack_di_report_vector (nn, Xx, Control) ;
+           }
+
+           /* -------------------------------------------------------------- */
+           /* warn about singular or near-singular matrices */
+           /* -------------------------------------------------------------- */
+
+           /* no warning is given if Control (1) is zero */
+
+           if (Control [UMFPACK_PRL] >= 1)
+           {
+               if (status == UMFPACK_WARNING_singular_matrix)
+               {
+                   sprintf (warning, "matrix is singular\n"
+                       "Try increasing Control (%d) and Control (%d).\n"
+                       "(Suppress this warning with Control (%d) = 0.)\n",
+                       1+UMFPACK_PIVOT_TOLERANCE,
+                       1+UMFPACK_SYM_PIVOT_TOLERANCE,
+                       1+UMFPACK_PRL) ;
+                   mexWarnMsgTxt (warning) ;
+               }
+               else if (Info [UMFPACK_RCOND] < DBL_EPSILON)
+               {
+                   sprintf (warning, "matrix is nearly singular, rcond = %g\n"
+                       "Try increasing Control (%d) and Control (%d).\n"
+                       "(Suppress this warning with Control (%d) = 0.)\n",
+                       Info [UMFPACK_RCOND],
+                       1+UMFPACK_PIVOT_TOLERANCE,
+                       1+UMFPACK_SYM_PIVOT_TOLERANCE,
+                       1+UMFPACK_PRL) ;
+                   mexWarnMsgTxt (warning) ;
+               }
+           }
+
+       }
+       else
+       {
+
+           /* -------------------------------------------------------------- */
+           /* get L, U, P, Q, and r */
+           /* -------------------------------------------------------------- */
+
+           if (A_is_complex)
+           {
+               status = umfpack_zi_get_lunz (&lnz, &unz, &ignore1, &ignore2,
+                   &ignore3, Numeric) ;
+           }
+           else
+           {
+               status = umfpack_di_get_lunz (&lnz, &unz, &ignore1, &ignore2,
+                   &ignore3, Numeric) ;
+           }
+
+           if (status < 0)
+           {
+               if (A_is_complex)
+               {
+                   umfpack_zi_free_numeric (&Numeric) ;
+               }
+               else
+               {
+                   umfpack_di_free_numeric (&Numeric) ;
+               }
+               error ("extracting LU factors failed", A_is_complex, nargout,
+                   pargout, Control, Info, status, do_info) ;
+               return ;
+           }
+
+           /* avoid malloc of zero-sized arrays */
+           lnz = MAX (lnz, 1) ;
+           unz = MAX (unz, 1) ;
+
+           /* get temporary space, for the *** ROW *** form of L */
+           Ltp = (int *) mxMalloc ((n_row+1) * sizeof (int)) ;
+           Ltj = (int *) mxMalloc (lnz * sizeof (int)) ;
+           Ltx = (double *) mxMalloc (lnz * sizeof (double)) ;
+           if (A_is_complex)
+           {
+               Ltz = (double *) mxMalloc (lnz * sizeof (double)) ;
+           }
+           else
+           {
+               Ltz = (double *) NULL ;
+           }
+
+           /* create permanent copy of the output matrix U */
+           pargout [1] = mxCreateSparse (n_inner, n_col, unz, Atype) ;
+           Up = mxGetJc (pargout [1]) ;
+           Ui = mxGetIr (pargout [1]) ;
+           Ux = mxGetPr (pargout [1]) ;
+           Uz = mxGetPi (pargout [1]) ;
+
+           /* temporary space for the integer permutation vectors */
+           P = (int *) mxMalloc (n_row * sizeof (int)) ;
+           Q = (int *) mxMalloc (n_col * sizeof (int)) ;
+
+           /* get scale factors, if requested */
+           status2 = UMFPACK_OK ;
+           if (!no_scale)
+           {
+               /* create a diagonal sparse matrix for the scale factors */
+               pargout [4] = mxCreateSparse (n_row, n_row, n_row, mxREAL) ;
+               Rp = mxGetJc (pargout [4]) ;
+               Ri = mxGetIr (pargout [4]) ;
+               for (i = 0 ; i < n_row ; i++)
+               {
+                   Rp [i] = i ;
+                   Ri [i] = i ;
+               }
+               Rp [n_row] = n_row ;
+               Rs = mxGetPr (pargout [4]) ;
+           }
+           else
+           {
+               Rs = (double *) NULL ;
+           }
+
+           /* get Lt, U, P, Q, and Rs from the numeric object */
+           if (A_is_complex)
+           {
+               status = umfpack_zi_get_numeric (Ltp, Ltj, Ltx, Ltz, Up, Ui, Ux,
+                   Uz, P, Q, (double *) NULL, (double *) NULL,
+                   &do_recip, Rs, Numeric) ;
+               umfpack_zi_free_numeric (&Numeric) ;
+           }
+           else
+           {
+               status = umfpack_di_get_numeric (Ltp, Ltj, Ltx, Up, Ui,
+                   Ux, P, Q, (double *) NULL,
+                   &do_recip, Rs, Numeric) ;
+               umfpack_di_free_numeric (&Numeric) ;
+           }
+
+           /* for the mexFunction, -DNRECIPROCAL must be set,
+            * so do_recip must be FALSE */
+
+           if (status < 0 || status2 < 0 || do_recip)
+           {
+               mxFree (Ltp) ;
+               mxFree (Ltj) ;
+               mxFree (Ltx) ;
+               if (Ltz) mxFree (Ltz) ;
+               mxFree (P) ;
+               mxFree (Q) ;
+               mxDestroyArray (pargout [1]) ;
+               error ("extracting LU factors failed", A_is_complex, nargout,
+                   pargout, Control, Info, status, do_info) ;
+               return ;
+           }
+
+           /* create sparse permutation matrix for P */
+           pargout [2] = mxCreateSparse (n_row, n_row, n_row, mxREAL) ;
+           Pp = mxGetJc (pargout [2]) ;
+           Pi = mxGetIr (pargout [2]) ;
+           Px = mxGetPr (pargout [2]) ;
+           for (k = 0 ; k < n_row ; k++)
+           {
+               Pp [k] = k ;
+               Px [k] = 1 ;
+               Pi [P [k]] = k ;
+           }
+           Pp [n_row] = n_row ;
+
+           /* create sparse permutation matrix for Q */
+           pargout [3] = mxCreateSparse (n_col, n_col, n_col, mxREAL) ;
+           Qp = mxGetJc (pargout [3]) ;
+           Qi = mxGetIr (pargout [3]) ;
+           Qx = mxGetPr (pargout [3]) ;
+           for (k = 0 ; k < n_col ; k++)
+           {
+               Qp [k] = k ;
+               Qx [k] = 1 ;
+               Qi [k] = Q [k] ;
+           }
+           Qp [n_col] = n_col ;
+
+           /* permanent copy of L */
+           pargout [0] = mxCreateSparse (n_row, n_inner, lnz, Atype) ;
+           Lp = mxGetJc (pargout [0]) ;
+           Li = mxGetIr (pargout [0]) ;
+           Lx = mxGetPr (pargout [0]) ;
+           Lz = mxGetPi (pargout [0]) ;
+
+           /* convert L from row form to column form */
+           if (A_is_complex)
+           {
+               /* non-conjugate array transpose */
+               status = umfpack_zi_transpose (n_inner, n_row, Ltp, Ltj, Ltx,
+                   Ltz, (int *) NULL, (int *) NULL, Lp, Li, Lx, Lz, FALSE) ;
+           }
+           else
+           {
+               status = umfpack_di_transpose (n_inner, n_row, Ltp, Ltj, Ltx,
+                   (int *) NULL, (int *) NULL, Lp, Li, Lx) ;
+           }
+
+           mxFree (Ltp) ;
+           mxFree (Ltj) ;
+           mxFree (Ltx) ;
+           if (Ltz) mxFree (Ltz) ;
+
+           if (status < 0)
+           {
+               mxFree (P) ;
+               mxFree (Q) ;
+               mxDestroyArray (pargout [0]) ;
+               mxDestroyArray (pargout [1]) ;
+               mxDestroyArray (pargout [2]) ;
+               mxDestroyArray (pargout [3]) ;
+               error ("constructing L failed", A_is_complex, nargout, pargout,
+                   Control, Info, status, do_info) ;
+               return ;
+           }
+
+           /* -------------------------------------------------------------- */
+           /* print L, U, P, and Q */
+           /* -------------------------------------------------------------- */
+
+           if (A_is_complex)
+           {
+               if (print_level >= 3) mexPrintf ("\nL: ") ;
+               (void) umfpack_zi_report_matrix (n_row, n_inner, Lp, Li,
+                   Lx, Lz, 1, Control) ;
+               if (print_level >= 3) mexPrintf ("\nU: ") ;
+               (void) umfpack_zi_report_matrix (n_inner, n_col,  Up, Ui,
+                   Ux, Uz, 1, Control) ;
+               if (print_level >= 3) mexPrintf ("\nP: ") ;
+               (void) umfpack_zi_report_perm (n_row, P, Control) ;
+               if (print_level >= 3) mexPrintf ("\nQ: ") ;
+               (void) umfpack_zi_report_perm (n_col, Q, Control) ;
+           }
+           else
+           {
+               if (print_level >= 3) mexPrintf ("\nL: ") ;
+               (void) umfpack_di_report_matrix (n_row, n_inner, Lp, Li,
+                   Lx, 1, Control) ;
+               if (print_level >= 3) mexPrintf ("\nU: ") ;
+               (void) umfpack_di_report_matrix (n_inner, n_col,  Up, Ui,
+                   Ux, 1, Control) ;
+               if (print_level >= 3) mexPrintf ("\nP: ") ;
+               (void) umfpack_di_report_perm (n_row, P, Control) ;
+               if (print_level >= 3) mexPrintf ("\nQ: ") ;
+               (void) umfpack_di_report_perm (n_col, Q, Control) ;
+           }
+
+           mxFree (P) ;
+           mxFree (Q) ;
+
+       }
+
+    }
+    else
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* return the symbolic factorization */
+       /* ------------------------------------------------------------------ */
+
+       Q = (int *) mxMalloc (n_col * sizeof (int)) ;
+       P = (int *) mxMalloc (n_row * sizeof (int)) ;
+       Front_npivcol = (int *) mxMalloc ((nn+1) * sizeof (int)) ;
+       Front_parent = (int *) mxMalloc ((nn+1) * sizeof (int)) ;
+       Front_1strow = (int *) mxMalloc ((nn+1) * sizeof (int)) ;
+       Front_leftmostdesc = (int *) mxMalloc ((nn+1) * sizeof (int)) ;
+       Chain_start = (int *) mxMalloc ((nn+1) * sizeof (int)) ;
+       Chain_maxrows = (int *) mxMalloc ((nn+1) * sizeof (int)) ;
+       Chain_maxcols = (int *) mxMalloc ((nn+1) * sizeof (int)) ;
+
+       if (A_is_complex)
+       {
+           status = umfpack_zi_get_symbolic (&ignore1, &ignore2, &ignore3,
+               &nz, &nfronts, &nchains, P, Q, Front_npivcol,
+               Front_parent, Front_1strow, Front_leftmostdesc,
+               Chain_start, Chain_maxrows, Chain_maxcols, Symbolic) ;
+           umfpack_zi_free_symbolic (&Symbolic) ;
+       }
+       else
+       {
+           status = umfpack_di_get_symbolic (&ignore1, &ignore2, &ignore3,
+               &nz, &nfronts, &nchains, P, Q, Front_npivcol,
+               Front_parent, Front_1strow, Front_leftmostdesc,
+               Chain_start, Chain_maxrows, Chain_maxcols, Symbolic) ;
+           umfpack_di_free_symbolic (&Symbolic) ;
+       }
+
+       if (status < 0)
+       {
+           mxFree (P) ;
+           mxFree (Q) ;
+           mxFree (Front_npivcol) ;
+           mxFree (Front_parent) ;
+           mxFree (Front_1strow) ;
+           mxFree (Front_leftmostdesc) ;
+           mxFree (Chain_start) ;
+           mxFree (Chain_maxrows) ;
+           mxFree (Chain_maxcols) ;
+           error ("extracting symbolic factors failed", A_is_complex, nargout,
+               pargout, Control, Info, status, do_info) ;
+           return ;
+       }
+
+       /* create sparse permutation matrix for P */
+       pargout [0] = mxCreateSparse (n_row, n_row, n_row, mxREAL) ;
+       Pp = mxGetJc (pargout [0]) ;
+       Pi = mxGetIr (pargout [0]) ;
+       Px = mxGetPr (pargout [0]) ;
+       for (k = 0 ; k < n_row ; k++)
+       {
+           Pp [k] = k ;
+           Px [k] = 1 ;
+           Pi [P [k]] = k ;
+       }
+       Pp [n_row] = n_row ;
+
+       /* create sparse permutation matrix for Q */
+       pargout [1] = mxCreateSparse (n_col, n_col, n_col, mxREAL) ;
+       Qp = mxGetJc (pargout [1]) ;
+       Qi = mxGetIr (pargout [1]) ;
+       Qx = mxGetPr (pargout [1]) ;
+       for (k = 0 ; k < n_col ; k++)
+       {
+           Qp [k] = k ;
+           Qx [k] = 1 ;
+           Qi [k] = Q [k] ;
+       }
+       Qp [n_col] = n_col ;
+
+       /* create Fr */
+       pargout [2] = mxCreateDoubleMatrix (nfronts+1, 4, mxREAL) ;
+
+       p1 = mxGetPr (pargout [2]) ;
+       p2 = p1 + nfronts + 1 ;
+       p3 = p2 + nfronts + 1 ;
+       p4 = p3 + nfronts + 1 ;
+       for (i = 0 ; i <= nfronts ; i++)
+       {
+           /* convert parent, 1strow, and leftmostdesc to 1-based */
+           p1 [i] = (double) (Front_npivcol [i]) ;
+           p2 [i] = (double) (Front_parent [i] + 1) ;
+           p3 [i] = (double) (Front_1strow [i] + 1) ;
+           p4 [i] = (double) (Front_leftmostdesc [i] + 1) ;
+       }
+
+       /* create Ch */
+       pargout [3] = mxCreateDoubleMatrix (nchains+1, 3, mxREAL) ;
+       p1 = mxGetPr (pargout [3]) ;
+       p2 = p1 + nchains + 1 ;
+       p3 = p2 + nchains + 1 ;
+       for (i = 0 ; i < nchains ; i++)
+       {
+           p1 [i] = (double) (Chain_start [i] + 1) ;   /* convert to 1-based */
+           p2 [i] = (double) (Chain_maxrows [i]) ;
+           p3 [i] = (double) (Chain_maxcols [i]) ;
+       }
+       p1 [nchains] = Chain_start [nchains] + 1 ;
+       p2 [nchains] = 0 ;
+       p3 [nchains] = 0 ;
+
+       mxFree (P) ;
+       mxFree (Q) ;
+       mxFree (Front_npivcol) ;
+       mxFree (Front_parent) ;
+       mxFree (Front_1strow) ;
+       mxFree (Front_leftmostdesc) ;
+       mxFree (Chain_start) ;
+       mxFree (Chain_maxrows) ;
+       mxFree (Chain_maxcols) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* report Info */
+    /* ---------------------------------------------------------------------- */
+
+    if (A_is_complex)
+    {
+       umfpack_zi_report_info (Control, Info) ;
+    }
+    else
+    {
+       umfpack_di_report_info (Control, Info) ;
+    }
+
+    if (do_info > 0)
+    {
+       /* return Info */
+       pargout [do_info] = mxCreateDoubleMatrix (1, UMFPACK_INFO, mxREAL) ;
+       OutInfo = mxGetPr (pargout [do_info]) ;
+       for (i = 0 ; i < UMFPACK_INFO ; i++)
+       {
+           OutInfo [i] = Info [i] ;
+       }
+    }
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/west0067.mat b/deal.II/contrib/umfpack/UMFPACK/MATLAB/west0067.mat
new file mode 100644 (file)
index 0000000..6cd8c88
Binary files /dev/null and b/deal.II/contrib/umfpack/UMFPACK/MATLAB/west0067.mat differ
diff --git a/deal.II/contrib/umfpack/UMFPACK/README b/deal.II/contrib/umfpack/UMFPACK/README
new file mode 100644 (file)
index 0000000..ff39cb6
--- /dev/null
@@ -0,0 +1,376 @@
+UMFPACK Version 4.3:  a set of routines solving sparse linear systems via LU
+    factorization.  Requires two other packages:  the BLAS (dense matrix
+    operations) and AMD (sparse matrix minimum degree ordering).  Includes
+    a C-callable and MATLAB interface, and a basic FORTRAN 77 interface to
+    a subset of the C-callable routines.
+
+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
+    UMFPACK/Make/Make.include and AMD/Make/Make.include (otherwise the BLAS
+    will not be used, and UMFPACK will be slow).  cd to this directory (UMFPACK)
+    and type "make" (or "make lib" if you do not have MATLAB).  To compile and
+    run a 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 UMFPACK/Make/Make.include, for more details
+    (including options for compiling 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.
+    This works on any system supported by MATLAB.
+
+--------------------------------------------------------------------------------
+
+UMFPACK Version 4.3 (Jan. 16, 2003),  Copyright (c) 2003 by Timothy A.
+Davis.  All Rights Reserved.
+
+UMFPACK License:
+
+    Your use or distribution of UMFPACK or any modified version of
+    UMFPACK implies that you agree to this License.
+
+    THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
+    EXPRESSED OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+
+    Permission is hereby granted to use or copy this program, provided
+    that the Copyright, this License, and the Availability of the original
+    version is retained on all copies.  User documentation of any code that
+    uses UMFPACK or any modified version of UMFPACK code must cite the
+    Copyright, this License, the Availability note, and "Used by permission."
+    Permission to modify the code and to distribute modified code is granted,
+    provided the Copyright, this License, and the Availability note are
+    retained, and a notice that the code was modified is included.  This
+    software was developed with support from the National Science Foundation,
+    and is provided to you free of charge.
+
+Availability:
+
+    http://www.cise.ufl.edu/research/sparse/umfpack
+
+    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.
+
+--------------------------------------------------------------------------------
+
+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.3 can use either AMD v1.0 or v1.1.
+
+--------------------------------------------------------------------------------
+
+This is the UMFPACK README 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 1.0
+    or Version 1.1
+
+Authors:
+
+    Timothy A. Davis (davis@cise.ufl.edu), University of Florida.
+
+    Includes a modified version of COLAMD V2.0, by Stefan I. Larimore and
+    Timothy A. Davis, University of Florida.  The COLAMD algorithm was developed
+    in collaboration with John Gilbert, Xerox Palo Alto Research Center, and
+    Esmond Ng, Lawrence Berkeley National Laboratory.
+
+    Includes AMD, by Timothy A. Davis, Patrick R. Amestoy, and Iain S. Duff.
+
+    UMFPACK Version 2.2.1 (MA38 in the Harwell Subroutine Library) is
+    co-authored with Iain S. Duff, Rutherford Appleton Laboratory.
+
+Acknowledgements:
+
+    This work was supported by the National Science Foundation, under
+    grants DMS-9504974, DMS-9803599, and CCR-0203270.
+
+    Portions of this work were done while on sabbatical at Stanford University
+    and Lawrence Berkeley National Laboratory (with funding from the SciDAC
+    program).  I would like to thank Gene Golub, Esmond Ng, and Horst Simon
+    for making this sabbatical possible.
+
+    I would also like to thank the many researchers who provided sparse
+    matrices from a wide range of domains and used earlier versions of UMFPACK/
+    MA38 in their applications, and thus assisted in the practical development
+    of the algorithm (see http://www.cise.ufl.edu/research/sparse, future
+    contributions of matrices are always welcome).
+
+    The MathWorks, Inc., provided a pre-release of MATLAB V6 which allowed me
+    to release the first umfpack mexFunction (v3.0) about 6 months earlier than
+    I had originally planned.  They also supported the extension of UMFPACK to
+    complex, singular, and rectangular matrices (UMFPACK v4.0).
+
+    Penny Anderson (The MathWorks, Inc.), Anshul Gupta (IBM), and Friedrich
+    Grund (WAIS) assisted in porting UMFPACK to different platforms.  Penny
+    Anderson also incorporated UMFPACK v4.0 into MATLAB, for lu, backslash (\),
+    and forward slash (/).
+
+--------------------------------------------------------------------------------
+Files and directories in the UMFPACK distribution:
+--------------------------------------------------------------------------------
+
+    ----------------------------------------------------------------------------
+    Subdirectories of the UMFPACK directory:
+    ----------------------------------------------------------------------------
+
+    Doc                documentation
+    Make       for compiling UMFPACK (a symbolic link to ../AMD/Make)
+    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     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)
+
+    ----------------------------------------------------------------------------
+    Make directory: for compiling the UMFPACK library (Lib/libumfpack.a)
+    ----------------------------------------------------------------------------
+
+    This is a symbolic link to the ../AMD/Make directory.  Refer to the
+    ../AMD/README file for a list of its contents.
+
+    ----------------------------------------------------------------------------
+    Source directory:
+    ----------------------------------------------------------------------------
+
+    GNUmakefile                        a nice Makefile, for GNU make
+    Makefile                   an ugly Unix Makefile (for older make's)
+
+    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_lunz.c         get nz's in L and U
+    umfpack_get_numeric.c      get Numeric object
+    umfpack_get_symbolic.c     get Symbolic object
+    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_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/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_lunz.h
+    umfpack_get_numeric.h
+    umfpack_get_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_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/long version)
+    umfpack_zi_demo.c          a full demo (complex/int version)
+    umfpack_zl_demo.c          a full demo (complex/long version)
+
+    umfpack_di_demo.out                umfpack_di_demo output, unmodified Make.include
+    umfpack_dl_demo.out                umfpack_dl_demo output, unmodified Make.include
+    umfpack_zi_demo.out                umfpack_zi_demo output, unmodified Make.include
+    umfpack_zl_demo.out                umfpack_zl_demo output, unmodified Make.include
+
+    umf4.c                     a demo (real/int) for Harwell/Boeing matrices
+    umf4.out                   output of "make hb", unmodified Make.include
+    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 Bai/qc324.cua, which is
+                               not included in this distribution, see
+                               http://www.cise.ufl.edu/research/sparse/matrices
+
+    umf4hb64.f                 64-bit version of umf4hb.f
+
+    ----------------------------------------------------------------------------
+    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)
+
+    luflop.m                   for "help luflop"
+    luflopmex.c                        luflop mexFunction, for computing LU flop count
+    lu_normest.m               1-norm estimate of A-L*U (by Hager & Davis).
+    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.m                  for "help umfpack"
+    umfpack_make.m             compile the umfpack mexFunction within MATLAB
+    umfpackmex.c               the umfpack mexFunction
+    umfpack_report.m           report statistics
+    umfpack_simple.m           a simple umfpack demo
+    umfpack_solve.m            x=A\b or b/A for arbitrary b
+    west0067.mat               sparse matrix for umfpack_demo.m
+
+    umfpack_demo.m.out         output of umfpack_demo.m
+    umfpack_simple.m.out       output of umfpack_simple
+
+    lcc_lib/lapacksyms.def     LAPACK definitions for lcc compiler (Windows)
+    lcc_lib/libmwlapack.lib    LAPACK definitions for lcc compiler (Windows)
+
+    ----------------------------------------------------------------------------
+    Lib directory:  libumfpack.a library placed here
+    ----------------------------------------------------------------------------
+
+    libumfpack.def             UMPFACK definitions for Windows
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/Makefile b/deal.II/contrib/umfpack/UMFPACK/Source/Makefile
new file mode 100644 (file)
index 0000000..a2801ea
--- /dev/null
@@ -0,0 +1,193 @@
+#-------------------------------------------------------------------------------
+# UMFPACK Makefile for compiling on Unix systems (for GNU Make)
+#-------------------------------------------------------------------------------
+
+include ../../../../common/Make.global_options
+
+#-------------------------------------------------------------------------------
+# 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/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/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/long and real/complex versions:
+UMF = $(UMF_CREATED) $(UMFCH)
+
+# user-callable umfpack_*.[ch] files (int/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_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/long and real/complex versions:
+UMFPACKW = umfpack_wsolve
+
+USER = $(UMFPACKW) $(UMFPACK)
+
+# user-callable, only one version for int/long, real/complex, *.[ch] files:
+GENERIC = umfpack_timer umfpack_tictoc
+
+#-------------------------------------------------------------------------------
+# include files:
+#-------------------------------------------------------------------------------
+
+INC = ../Include/umfpack.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/Source/amd_internal.h ../../AMD/Include/amd.h
+
+#-------------------------------------------------------------------------------
+# object files for each version
+#-------------------------------------------------------------------------------
+
+DI = $(addprefix $D/lib/umfpack/, $(addsuffix .$(OBJEXT), $(subst umf_,umf_di_,$(UMF)) $(subst umfpack_,umfpack_di_,$(USER))))
+DL = $(addprefix $D/lib/umfpack/, $(addsuffix .$(OBJEXT), $(subst umf_,umf_dl_,$(UMF)) $(subst umfpack_,umfpack_dl_,$(USER))))
+I  = $(addprefix $D/lib/umfpack/, $(addsuffix .$(OBJEXT), $(subst umf_,umf_i_,$(UMFINT))))
+L  = $(addprefix $D/lib/umfpack/, $(addsuffix .$(OBJEXT), $(subst umf_,umf_l_,$(UMFINT))))
+GN = $(addprefix $D/lib/umfpack/, $(addsuffix .$(OBJEXT), $(subst umfpack_,umfpack_gn_,$(GENERIC))))
+
+#-------------------------------------------------------------------------------
+# compile each int and long routine (with no real/complex version)
+#-------------------------------------------------------------------------------
+
+$D/lib/umfpack/umf_i_%.$(OBJEXT): umf_%.c $(INC)
+       @echo =====umfpack==========optimized==$(MT)== $(<F)
+       $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDINT -c $< -o $@
+
+$D/lib/umfpack/umf_l_%.$(OBJEXT): umf_%.c $(INC)
+       @echo =====umfpack==========optimized==$(MT)== $(<F)
+       $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDLONG -c $< -o $@
+
+#-------------------------------------------------------------------------------
+# compile each routine in the DI version
+#-------------------------------------------------------------------------------
+
+$D/lib/umfpack/umf_di_%.$(OBJEXT): umf_%.c $(INC)
+       @echo =====umfpack==========optimized==$(MT)== $(<F)
+       $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDINT -c $< -o $@
+
+$D/lib/umfpack/umf_di_%hsolve.$(OBJEXT): umf_%tsolve.c $(INC)
+       @echo =====umfpack==========optimized==$(MT)== $(<F)
+       $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDINT -DCONJUGATE_SOLVE -c $< -o $@
+
+$D/lib/umfpack/umf_di_triplet_map_x.$(OBJEXT): umf_triplet.c $(INC)
+       @echo =====umfpack==========optimized==$(MT)== $(<F)
+       $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDINT -DDO_MAP -DDO_VALUES -c $< -o $@
+
+$D/lib/umfpack/umf_di_triplet_map_nox.$(OBJEXT): umf_triplet.c $(INC)
+       @echo =====umfpack==========optimized==$(MT)== $(<F)
+       $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDINT -DDO_MAP -c $< -o $@
+
+$D/lib/umfpack/umf_di_triplet_nomap_x.$(OBJEXT): umf_triplet.c $(INC)
+       @echo =====umfpack==========optimized==$(MT)== $(<F)
+       $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDINT -DDO_VALUES -c $< -o $@
+
+$D/lib/umfpack/umf_di_triplet_nomap_nox.$(OBJEXT): umf_triplet.c $(INC)
+       @echo =====umfpack==========optimized==$(MT)== $(<F)
+       $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDINT -c $< -o $@
+
+$D/lib/umfpack/umf_di_assemble_fixq.$(OBJEXT): umf_assemble.c $(INC)
+       @echo =====umfpack==========optimized==$(MT)== $(<F)
+       $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDINT -DFIXQ -c $< -o $@
+
+$D/lib/umfpack/umf_di_store_lu_drop.$(OBJEXT): umf_store_lu.c $(INC)
+       @echo =====umfpack==========optimized==$(MT)== $(<F)
+       $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDINT -DDROP -c $< -o $@
+
+$D/lib/umfpack/umfpack_di_wsolve.$(OBJEXT): umfpack_solve.c $(INC)
+       @echo =====umfpack==========optimized==$(MT)== $(<F)
+       $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDINT -DWSOLVE -c $< -o $@
+
+$D/lib/umfpack/umfpack_di_%.$(OBJEXT): umfpack_%.c $(INC)
+       @echo =====umfpack==========optimized==$(MT)== $(<F)
+       $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDINT -c $< -o $@
+
+#-------------------------------------------------------------------------------
+# compile each routine in the DL version
+#-------------------------------------------------------------------------------
+
+$D/lib/umfpack/umf_dl_%.$(OBJEXT): umf_%.c $(INC)
+       @echo =====umfpack==========optimized==$(MT)== $(<F)
+       $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDLONG -c $< -o $@
+
+$D/lib/umfpack/umf_dl_%hsolve.$(OBJEXT): umf_%tsolve.c $(INC)
+       @echo =====umfpack==========optimized==$(MT)== $(<F)
+       $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDLONG -DCONJUGATE_SOLVE -c $< -o $@
+
+$D/lib/umfpack/umf_dl_triplet_map_x.$(OBJEXT): umf_triplet.c $(INC)
+       @echo =====umfpack==========optimized==$(MT)== $(<F)
+       $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDLONG -DDO_MAP -DDO_VALUES -c $< -o $@
+
+$D/lib/umfpack/umf_dl_triplet_map_nox.$(OBJEXT): umf_triplet.c $(INC)
+       @echo =====umfpack==========optimized==$(MT)== $(<F)
+       $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDLONG -DDO_MAP -c $< -o $@
+
+$D/lib/umfpack/umf_dl_triplet_nomap_x.$(OBJEXT): umf_triplet.c $(INC)
+       @echo =====umfpack==========optimized==$(MT)== $(<F)
+       $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDLONG -DDO_VALUES -c $< -o $@
+
+$D/lib/umfpack/umf_dl_triplet_nomap_nox.$(OBJEXT): umf_triplet.c $(INC)
+       @echo =====umfpack==========optimized==$(MT)== $(<F)
+       $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDLONG -c $< -o $@
+
+$D/lib/umfpack/umf_dl_assemble_fixq.$(OBJEXT): umf_assemble.c $(INC)
+       @echo =====umfpack==========optimized==$(MT)== $(<F)
+       $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDLONG -DFIXQ -c $< -o $@
+
+$D/lib/umfpack/umf_dl_store_lu_drop.$(OBJEXT): umf_store_lu.c $(INC)
+       @echo =====umfpack==========optimized==$(MT)== $(<F)
+       $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDLONG -DDROP -c $< -o $@
+
+$D/lib/umfpack/umfpack_dl_wsolve.$(OBJEXT): umfpack_solve.c $(INC)
+       @echo =====umfpack==========optimized==$(MT)== $(<F)
+       $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDLONG -DWSOLVE -c $< -o $@
+
+$D/lib/umfpack/umfpack_dl_%.$(OBJEXT): umfpack_%.c $(INC)
+       @echo =====umfpack==========optimized==$(MT)== $(<F)
+       $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDLONG -c $< -o $@
+
+#-------------------------------------------------------------------------------
+# Create the generic routines (GN) using a generic rule
+#-------------------------------------------------------------------------------
+
+$D/lib/umfpack/umfpack_gn_%.$(OBJEXT): umfpack_%.c $(INC)
+       @echo =====umfpack==========optimized==$(MT)== $(<F)
+       $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -c $< -o $@
+
+#-------------------------------------------------------------------------------
+# Create the libumfpack.a library
+#-------------------------------------------------------------------------------
+
+all: $(I) $(L) $(GN) $(DI) $(DL)
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_2by2.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_2by2.c
new file mode 100644 (file)
index 0000000..e3111a7
--- /dev/null
@@ -0,0 +1,864 @@
+/* ========================================================================== */
+/* === UMF_2by2 ============================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*  Not user-callable.  Computes a row permutation P so that A (P,:) has a
+ *  mostly zero-free diagonal, with large entries on the diagonal.  It does this
+ *  by swapping pairs of rows.  Once a row is swapped it is not swapped again.
+ *  This is a "cheap" assignment, not a complete max. transversal or
+ *  bi-partite matching.  It is only a partial matching.  For most matrices
+ *  for which this algorithm is used, however, the matching is complete (in
+ *  UMFPACK this algorithm is used for matrices with roughly symmetric pattern,
+ *  and these matrices typically have a mostly-zero-free diagonal to begin with.
+ *  This algorithm is not meant to be used on arbitrary unsymmetric matrices
+ *  (for those matrices, UMFPACK uses its unsymmetric strategy and does not
+ *  use this algorithm).
+ *
+ *  Even if incomplete, the matching is usually good enough for UMFPACK's
+ *  symmetric strategy, which can easily pivot off the diagonal during numerical
+ *  factorization if it finds a weak diagonal entry.
+ *
+ *  The algorithms works as follows.  First, row scaling factors are computed,
+ *  and weak diagonal entries are found.  A weak entry is a value A(k,k) whose
+ *  absolute value is < tol * max (abs (A (:,k))).  For each weak diagonal k in
+ *  increasing order of degree in A+A', the algorithm finds an index j such
+ *  that A (k,j) and A (j,k) are "large" (greater than or equal to tol times
+ *  the largest magnitude in their columns).  Row j must also not have already
+ *  been swapped.  Rows j and k are then swapped.  If we come to a diagonal k
+ *  that has already been swapped, then it is not modified.  This case occurs
+ *  for "oxo" pivots:
+ *
+ *    k j
+ *  k o x
+ *  j x o
+ *
+ *  which are swapped once to obtain
+ *
+ *    k j
+ *  j x o
+ *  k o x
+ *
+ *  These two rows are then not modified any further (A (j,j) was weak, but
+ *  after one swap the permuted the jth diagonal entry is strong.
+ *
+ *  This algorithm only works on square matrices (real, complex, or pattern-
+ *  only).  The numerical values are optional.  If not present, each entry is
+ *  treated as numerically acceptable (tol is ignored), and the algorithm
+ *  operates by just using the pattern, not the values.  Each column of the
+ *  input matrix A must be sorted, with no duplicate entries.  The matrix A
+ *  can be optionally scaled prior to the numerical test.  The matrix A (:,P)
+ *  has the same diagonal entries as A (:,P), except in different order.  So
+ *  the output permutation P can also be used to swap the columns of A.
+ */
+
+#include "umf_internal.h"
+
+#ifndef NDEBUG
+#include "umf_is_permutation.h"
+#endif
+
+/* x is "weak" if it is less than ctol.  If x or ctol are NaN, then define
+ * x as not "weak".  This is a rather arbitrary choice, made to simplify the
+ * computation.  On all but a PC with Microsoft C/C++, this test becomes
+ * ((x) - ctol < 0). */
+#define WEAK(x,ctol) (SCALAR_IS_LTZERO ((x)-(ctol)))
+
+/* For flag value in Next [col] */
+#define IS_WEAK -2
+
+/* ========================================================================== */
+/* === two_by_two =========================================================== */
+/* ========================================================================== */
+
+PRIVATE Int two_by_two     /* returns # unmatched weak diagonals */
+(
+    /* input, not modified */
+    Int n2,            /* C is n2-by-n2 */
+    Int Cp [ ],                /* size n2+1, column pointers for C */
+    Int Ci [ ],                /* size snz = Cp [n2], row indices for C */
+    Int Degree [ ],    /* Degree [i] = degree of row i of C+C' */
+
+    /* input, not defined on output */
+    Int Next [ ],      /* Next [k] == IS_WEAK if k is a weak diagonal */
+    Int Ri [ ],                /* Ri [i] is the length of row i in C */
+
+    /* output, not defined on input */
+    Int P [ ],
+
+    /* workspace, not defined on input or output */
+    Int Rp [ ],
+    Int Head [ ]
+)
+{
+    Int deg, newcol, row, col, p, p2, unmatched, k, j, j2, j_best, best, jdiff,
+       jdiff_best, jdeg, jdeg_best, cp, cp1, cp2, rp, rp1, rp2, maxdeg,
+       mindeg ;
+
+    /* ---------------------------------------------------------------------- */
+    /* place weak diagonals in the degree lists */
+    /* ---------------------------------------------------------------------- */
+
+    for (deg = 0 ; deg < n2 ; deg++)
+    {
+       Head [deg] = EMPTY ;
+    }
+
+    maxdeg = 0 ;
+    mindeg = Int_MAX ;
+    for (newcol = n2-1 ; newcol >= 0 ; newcol--)
+    {
+       if (Next [newcol] == IS_WEAK)
+       {
+           /* add this column to the list of weak nodes */
+           DEBUGm1 (("    newcol "ID" has a weak diagonal deg "ID"\n",
+               newcol, deg)) ;
+           deg = Degree [newcol] ;
+           ASSERT (deg >= 0 && deg < n2) ;
+           Next [newcol] = Head [deg] ;
+           Head [deg] = newcol ;
+           maxdeg = MAX (maxdeg, deg) ;
+           mindeg = MIN (mindeg, deg) ;
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* construct R = C' (C = strong entries in pruned submatrix) */
+    /* ---------------------------------------------------------------------- */
+
+    /* Ri [0..n2-1] is the length of each row of R */
+    /* use P as temporary pointer into the row form of R [ */
+    Rp [0] = 0 ;
+    for (row = 0 ; row < n2 ; row++)
+    {
+       Rp [row+1] = Rp [row] + Ri [row] ;
+       P [row] = Rp [row] ;
+    }
+    /* Ri no longer needed for row counts */
+
+    /* all entries in C are strong */
+    for (col = 0 ; col < n2 ; col++)
+    {
+       p2 = Cp [col+1] ;
+       for (p = Cp [col] ; p < p2 ; p++)
+       {
+           /* place the column index in row = Ci [p] */
+           Ri [P [Ci [p]]++] = col ;
+       }
+    }
+
+    /* contents of P no longer needed ] */
+
+#ifndef NDEBUG
+    DEBUG0 (("==================R: row form of strong entries in A:\n")) ;
+    UMF_dump_col_matrix ((double *) NULL,
+#ifdef COMPLEX
+           (double *) NULL,
+#endif
+           Ri, Rp, n2, n2, Rp [n2]) ;
+#endif
+    ASSERT (AMD_valid (n2, n2, Rp, Ri)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* for each weak diagonal, find a pair of strong off-diagonal entries */
+    /* ---------------------------------------------------------------------- */
+
+    for (row = 0 ; row < n2 ; row++)
+    {
+       P [row] = EMPTY ;
+    }
+
+    unmatched = 0 ;
+    best = EMPTY ;
+    jdiff = EMPTY ;
+    jdeg = EMPTY ;
+
+    for (deg = mindeg ; deg <= maxdeg ; deg++)
+    {
+       /* find the next weak diagonal of lowest degree */
+       DEBUGm2 (("---------------------------------- Deg: "ID"\n", deg)) ;
+       for (k = Head [deg] ; k != EMPTY ; k = Next [k])
+       {
+           DEBUGm2 (("k: "ID"\n", k)) ;
+           if (P [k] == EMPTY)
+           {
+               /* C (k,k) is a weak diagonal entry.  Find an index j != k such
+                * that C (j,k) and C (k,j) are both strong, and also such
+                * that Degree [j] is minimized.  In case of a tie, pick
+                * the smallest index j.  C and R contain the pattern of
+                * strong entries only.
+                *
+                * Note that row k of R and column k of C are both sorted. */
+
+               DEBUGm4 (("===== Weak diagonal k = "ID"\n", k)) ;
+               DEBUG1 (("Column k of C:\n")) ;
+               for (p = Cp [k] ; p < Cp [k+1] ; p++)
+               {
+                   DEBUG1 (("    "ID": deg "ID"\n", Ci [p], Degree [Ci [p]]));
+               }
+               DEBUG1 (("Row k of R (strong entries only):\n")) ;
+               for (p = Rp [k] ; p < Rp [k+1] ; p++)
+               {
+                   DEBUG1 (("    "ID": deg "ID"\n", Ri [p], Degree [Ri [p]]));
+               }
+
+               /* no (C (k,j), C (j,k)) pair exists yet */
+               j_best = EMPTY ;
+               jdiff_best = Int_MAX ;
+               jdeg_best = Int_MAX ;
+
+               /* pointers into column k (including values) */
+               cp1 = Cp [k] ;
+               cp2 = Cp [k+1] ;
+               cp = cp1 ;
+
+               /* pointers into row k (strong entries only, no values) */
+               rp1 = Rp [k] ;
+               rp2 = Rp [k+1] ;
+               rp = rp1 ;
+
+               /* while entries searched in column k and row k */
+               while (TRUE)
+               {
+
+                   if (cp >= cp2)
+                   {
+                       /* no more entries in this column */
+                       break ;
+                   }
+
+                   /* get C (j,k), which is strong */
+                   j = Ci [cp] ;
+
+                   if (rp >= rp2)
+                   {
+                       /* no more entries in this column */
+                       break ;
+                   }
+
+                   /* get R (k,j2), which is strong */
+                   j2 = Ri [rp] ;
+
+                   if (j < j2)
+                   {
+                       /* C (j,k) is strong, but R (k,j) is not strong */
+                       cp++ ;
+                       continue ;
+                   }
+
+                   if (j2 < j)
+                   {
+                       /* C (k,j2) is strong, but R (j2,k) is not strong */
+                       rp++ ;
+                       continue ;
+                   }
+
+                   /* j == j2: C (j,k) is strong and R (k,j) is strong */
+
+                   best = FALSE ;
+
+                   if (P [j] == EMPTY)
+                   {
+                       /* j has not yet been matched */
+                       jdeg = Degree [j] ;
+                       jdiff = SCALAR_ABS (k-j) ;
+
+                       DEBUG1 (("Try candidate j "ID" deg "ID" diff "ID
+                                   "\n", j, jdeg, jdiff)) ;
+
+                       if (j_best == EMPTY)
+                       {
+                           /* this is the first candidate seen */
+                           DEBUG1 (("   first\n")) ;
+                           best = TRUE ;
+                       }
+                       else
+                       {
+                           if (jdeg < jdeg_best)
+                           {
+                               /* the degree of j is best seen so far. */
+                               DEBUG1 (("   least degree\n")) ;
+                               best = TRUE ;
+                           }
+                           else if (jdeg == jdeg_best)
+                           {
+                               /* degree of j and j_best are the same */
+                               /* tie break by nearest node number */
+                               if (jdiff < jdiff_best)
+                               {
+                                   DEBUG1 (("   tie degree, closer\n")) ;
+                                   best = TRUE ;
+                               }
+                               else if (jdiff == jdiff_best)
+                               {
+                                   /* |j-k| = |j_best-k|.  For any given k
+                                    * and j_best there is only one other j
+                                    * than can be just as close as j_best.
+                                    * Tie break by picking the smaller of
+                                    * j and j_best */
+                                   DEBUG1 (("   tie degree, as close\n"));
+                                   best = j < j_best ;
+                               }
+                           }
+                           else
+                           {
+                               /* j has higher degree than best so far */
+                               best = FALSE ;
+                           }
+                       }
+                   }
+
+                   if (best)
+                   {
+                       /* j is best match for k */
+                       /* found a strong pair, A (j,k) and A (k,j) */
+                       DEBUG1 ((" --- Found pair k: "ID" j: " ID
+                           " jdeg: "ID" jdiff: "ID"\n",
+                           k, j, jdeg, jdiff)) ;
+                       ASSERT (jdiff != EMPTY) ;
+                       ASSERT (jdeg != EMPTY) ;
+                       j_best = j ;
+                       jdeg_best = jdeg ;
+                       jdiff_best = jdiff ;
+                   }
+
+                   /* get the next entries in column k and row k */
+                   cp++ ;
+                   rp++ ;
+               }
+
+               /* save the pair (j,k), if we found one */
+               if (j_best != EMPTY)
+               {
+                   j = j_best ;
+                   DEBUGm4 ((" --- best pair j: "ID" for k: "ID"\n", j, k)) ;
+                   P [k] = j ;
+                   P [j] = k ;
+               }
+               else
+               {
+                   /* no match was found for k */
+                   unmatched++ ;
+               }
+           }
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* finalize the row permutation, P */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = 0 ; k < n2 ; k++)
+    {
+       if (P [k] == EMPTY)
+       {
+           P [k] = k ;
+       }
+    }
+    ASSERT (UMF_is_permutation (P, Rp, n2, n2)) ;
+
+    return (unmatched) ;
+}
+
+
+/* ========================================================================== */
+/* === UMF_2by2 ============================================================= */
+/* ========================================================================== */
+
+GLOBAL void UMF_2by2
+(
+    /* input, not modified: */
+    Int n,                 /* A is n-by-n */
+    const Int Ap [ ],      /* size n+1 */
+    const Int Ai [ ],      /* size nz = Ap [n] */
+    const double Ax [ ],    /* size nz if present */
+#ifdef COMPLEX
+    const double Az [ ],    /* size nz if present */
+#endif
+    double tol,                /* tolerance for determining whether or not an
+                        * entry is numerically acceptable.  If tol <= 0
+                        * then all numerical values ignored. */
+    Int scale,         /* scaling to perform (none, sum, or max) */
+    Int Cperm1 [ ],    /* singleton permutations */
+#ifndef NDEBUG
+    Int Rperm1 [ ],    /* not needed, since Rperm1 = Cperm1 for submatrix S */
+#endif
+    Int InvRperm1 [ ], /* inverse of Rperm1 */
+    Int n1,            /* number of singletons */
+    Int nempty,                /* number of empty rows/cols */
+
+    /* input, contents undefined on output: */
+    Int Degree [ ],    /* Degree [j] is the number of off-diagonal
+                        * entries in row/column j of S+S', where
+                        * where S = A (Cperm1 [n1..], Rperm1 [n1..]).
+                        * Note that S is not used, nor formed. */
+
+    /* output: */
+    Int P [ ],         /* P [k] = i means original row i is kth row in S(P,:)
+                        * where S = A (Cperm1 [n1..], Rperm1 [n1..]) */
+    Int *p_nweak,
+    Int *p_unmatched,
+
+    /* workspace (not defined on input or output): */
+    Int Ri [ ],                /* of size >= max (nz, n) */
+    Int Rp [ ],                /* of size n+1 */
+    double Rs [ ],     /* of size n if present.  Rs = sum (abs (A),2) or
+                        * max (abs (A),2), the sum or max of each row.  Unused
+                        * if scale is equal to UMFPACK_SCALE_NONE. */
+    Int Head [ ],      /* of size n.  Head pointers for bucket sort */
+    Int Next [ ],      /* of size n.  Next pointers for bucket sort */
+    Int Ci [ ],                /* size nz */
+    Int Cp [ ]         /* size n+1 */
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int k, p, row, col, do_values, do_sum, do_max, do_scale, nweak, weak,
+       p1, p2, dfound, unmatched, n2, oldrow, newrow, oldcol, newcol, pp ;
+
+    double cmax, value, rs, ctol, dvalue ;
+    Entry aij ;
+
+#ifndef NRECIPROCAL
+    Int do_recip = FALSE ;
+#endif
+
+#ifndef NDEBUG
+    /* UMF_debug += 99 ; */
+    DEBUGm3 (("\n ==================================UMF_2by2: tol %g\n", tol)) ;
+    ASSERT (AMD_valid (n, n, Ap, Ai)) ;
+    for (k = n1 ; k < n - nempty ; k++)
+    {
+       ASSERT (Cperm1 [k] == Rperm1 [k]) ;
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* determine scaling options */
+    /* ---------------------------------------------------------------------- */
+
+    /* use the values, but only if they are present */
+    /* ignore the values if tol <= 0 */
+    do_values = (tol > 0)
+       && (Ax != (double *) NULL)
+#ifdef COMPLEX
+       && (Az != (double *) NULL)
+#endif
+    ;
+    if (do_values && (Rs != (double *) NULL))
+    {
+       do_sum = (scale == UMFPACK_SCALE_SUM) ;
+       do_max = (scale == UMFPACK_SCALE_MAX) ;
+    }
+    else
+    {
+       /* no scaling */
+       do_sum = FALSE ;
+       do_max = FALSE ;
+    }
+    do_scale = do_max || do_sum ;
+    DEBUGm3 (("do_values "ID" do_sum "ID" do_max "ID" do_scale "ID"\n",
+       do_values, do_sum, do_max, do_scale)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the row scaling, if requested */
+    /* ---------------------------------------------------------------------- */
+
+    /* see also umf_kernel_init */
+
+    if (do_scale)
+    {
+#ifndef NRECIPROCAL
+       double rsmin ;
+#endif
+       for (row = 0 ; row < n ; row++)
+       {
+           Rs [row] = 0.0 ;
+       }
+       for (col = 0 ; col < n ; col++)
+       {
+           p2 = Ap [col+1] ;
+           for (p = Ap [col] ; p < p2 ; p++)
+           {
+               row = Ai [p] ;
+               ASSIGN (aij, Ax [p], Az [p]) ;
+               APPROX_ABS (value, aij) ;
+               rs = Rs [row] ;
+               if (!SCALAR_IS_NAN (rs))
+               {
+                   if (SCALAR_IS_NAN (value))
+                   {
+                       /* if any entry in a row is NaN, then the scale factor
+                        * for the row is NaN.  It will be set to 1 later. */
+                       Rs [row] = value ;
+                   }
+                   else if (do_max)
+                   {
+                       Rs [row] = MAX (rs, value) ;
+                   }
+                   else
+                   {
+                       Rs [row] += value ;
+                   }
+               }
+           }
+       }
+#ifndef NRECIPROCAL
+       rsmin = Rs [0] ;
+       if (SCALAR_IS_ZERO (rsmin) || SCALAR_IS_NAN (rsmin))
+       {
+           rsmin = 1.0 ;
+       }
+#endif
+       for (row = 0 ; row < n ; row++)
+       {
+           /* do not scale an empty row, or a row with a NaN */
+           rs = Rs [row] ;
+           if (SCALAR_IS_ZERO (rs) || SCALAR_IS_NAN (rs))
+           {
+               Rs [row] = 1.0 ;
+           }
+#ifndef NRECIPROCAL
+           rsmin = MIN (rsmin, Rs [row]) ;
+#endif
+       }
+
+#ifndef NRECIPROCAL
+       /* multiply by the reciprocal if Rs is not too small */
+       do_recip = (rsmin >= RECIPROCAL_TOLERANCE) ;
+       if (do_recip)
+       {
+           /* invert the scale factors */
+           for (row = 0 ; row < n ; row++)
+           {
+               Rs [row] = 1.0 / Rs [row] ;
+           }
+       }
+#endif
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the max in each column and find diagonal */
+    /* ---------------------------------------------------------------------- */
+
+    nweak = 0 ;
+
+#ifndef NDEBUG
+    for (k = 0 ; k < n ; k++)
+    {
+       ASSERT (Rperm1 [k] >= 0 && Rperm1 [k] < n) ;
+       ASSERT (InvRperm1 [Rperm1 [k]] == k) ;
+    }
+#endif
+
+    n2 = n - n1 - nempty ;
+
+    /* use Ri to count the number of strong entries in each row */
+    for (row = 0 ; row < n2 ; row++)
+    {
+       Ri [row] = 0 ;
+    }
+
+    pp = 0 ;
+    ctol = 0 ;
+    dvalue = 1 ;
+
+    /* construct C = pruned submatrix, strong values only, column form */
+
+    for (k = n1 ; k < n - nempty ; k++)
+    {
+       oldcol = Cperm1 [k] ;
+       newcol = k - n1 ;
+       Next [newcol] = EMPTY ;
+       DEBUGm1 (("Column "ID" newcol "ID" oldcol "ID"\n", k, newcol, oldcol)) ;
+
+       Cp [newcol] = pp ;
+
+       dfound = FALSE ;
+       p1 = Ap [oldcol] ;
+       p2 = Ap [oldcol+1] ;
+       if (do_values)
+       {
+           cmax = 0 ;
+           dvalue = 0 ;
+
+           if (!do_scale)
+           {
+               /* no scaling */
+               for (p = p1 ; p < p2 ; p++)
+               {
+                   oldrow = Ai [p] ;
+                   ASSERT (oldrow >= 0 && oldrow < n) ;
+                   newrow = InvRperm1 [oldrow] - n1 ;
+                   ASSERT (newrow >= -n1 && newrow < n2) ;
+                   if (newrow < 0) continue ;
+                   ASSIGN (aij, Ax [p], Az [p]) ;
+                   APPROX_ABS (value, aij) ;
+                   /* if either cmax or value is NaN, define cmax as NaN */
+                   if (!SCALAR_IS_NAN (cmax))
+                   {
+                       if (SCALAR_IS_NAN (value))
+                       {
+                           cmax = value ;
+                       }
+                       else
+                       {
+                           cmax = MAX (cmax, value) ;
+                       }
+                   }
+                   if (oldrow == oldcol)
+                   {
+                       /* we found the diagonal entry in this column */
+                       dvalue = value ;
+                       dfound = TRUE ;
+                       ASSERT (newrow == newcol) ;
+                   }
+               }
+           }
+#ifndef NRECIPROCAL
+           else if (do_recip)
+           {
+               /* multiply by the reciprocal */
+               for (p = p1 ; p < p2 ; p++)
+               {
+                   oldrow = Ai [p] ;
+                   ASSERT (oldrow >= 0 && oldrow < n) ;
+                   newrow = InvRperm1 [oldrow] - n1 ;
+                   ASSERT (newrow >= -n1 && newrow < n2) ;
+                   if (newrow < 0) continue ;
+                   ASSIGN (aij, Ax [p], Az [p]) ;
+                   APPROX_ABS (value, aij) ;
+                   value *= Rs [oldrow] ;
+                   /* if either cmax or value is NaN, define cmax as NaN */
+                   if (!SCALAR_IS_NAN (cmax))
+                   {
+                       if (SCALAR_IS_NAN (value))
+                       {
+                           cmax = value ;
+                       }
+                       else
+                       {
+                           cmax = MAX (cmax, value) ;
+                       }
+                   }
+                   if (oldrow == oldcol)
+                   {
+                       /* we found the diagonal entry in this column */
+                       dvalue = value ;
+                       dfound = TRUE ;
+                       ASSERT (newrow == newcol) ;
+                   }
+               }
+           }
+#endif
+           else
+           {
+               /* divide instead */
+               for (p = p1 ; p < p2 ; p++)
+               {
+                   oldrow = Ai [p] ;
+                   ASSERT (oldrow >= 0 && oldrow < n) ;
+                   newrow = InvRperm1 [oldrow] - n1 ;
+                   ASSERT (newrow >= -n1 && newrow < n2) ;
+                   if (newrow < 0) continue ;
+                   ASSIGN (aij, Ax [p], Az [p]) ;
+                   APPROX_ABS (value, aij) ;
+                   value /= Rs [oldrow] ;
+                   /* if either cmax or value is NaN, define cmax as NaN */
+                   if (!SCALAR_IS_NAN (cmax))
+                   {
+                       if (SCALAR_IS_NAN (value))
+                       {
+                           cmax = value ;
+                       }
+                       else
+                       {
+                           cmax = MAX (cmax, value) ;
+                       }
+                   }
+                   if (oldrow == oldcol)
+                   {
+                       /* we found the diagonal entry in this column */
+                       dvalue = value ;
+                       dfound = TRUE ;
+                       ASSERT (newrow == newcol) ;
+                   }
+               }
+           }
+
+           ctol = tol * cmax ;
+           DEBUGm1 (("    cmax col "ID" %g  ctol %g\n", oldcol, cmax, ctol)) ;
+       }
+       else
+       {
+           for (p = p1 ; p < p2 ; p++)
+           {
+               oldrow = Ai [p] ;
+               ASSERT (oldrow >= 0 && oldrow < n) ;
+               newrow = InvRperm1 [oldrow] - n1 ;
+               ASSERT (newrow >= -n1 && newrow < n2) ;
+               if (newrow < 0) continue ;
+               Ci [pp++] = newrow ;
+               if (oldrow == oldcol)
+               {
+                   /* we found the diagonal entry in this column */
+                   ASSERT (newrow == newcol) ;
+                   dfound = TRUE ;
+               }
+               /* count the entries in each column */
+               Ri [newrow]++ ;
+           }
+       }
+
+       /* ------------------------------------------------------------------ */
+       /* flag the weak diagonals */
+       /* ------------------------------------------------------------------ */
+
+       if (!dfound)
+       {
+           /* no diagonal entry present */
+           weak = TRUE ;
+       }
+       else
+       {
+           /* diagonal entry is present, check its value */
+           weak = (do_values) ?  WEAK (dvalue, ctol) : FALSE ;
+       }
+       if (weak)
+       {
+           /* flag this column as weak */
+           DEBUG0 (("Weak!\n")) ;
+           Next [newcol] = IS_WEAK ;
+           nweak++ ;
+       }
+
+       /* ------------------------------------------------------------------ */
+       /* count entries in each row that are not numerically weak */
+       /* ------------------------------------------------------------------ */
+
+       if (do_values)
+       {
+           if (!do_scale)
+           {
+               /* no scaling */
+               for (p = p1 ; p < p2 ; p++)
+               {
+                   oldrow = Ai [p] ;
+                   newrow = InvRperm1 [oldrow] - n1 ;
+                   if (newrow < 0) continue ;
+                   ASSIGN (aij, Ax [p], Az [p]) ;
+                   APPROX_ABS (value, aij) ;
+                   weak = WEAK (value, ctol) ;
+                   if (!weak)
+                   {
+                       DEBUG0 (("    strong: row "ID": %g\n", oldrow, value)) ;
+                       Ci [pp++] = newrow ;
+                       Ri [newrow]++ ;
+                   }
+               }
+           }
+#ifndef NRECIPROCAL
+           else if (do_recip)
+           {
+               /* multiply by the reciprocal */
+               for (p = p1 ; p < p2 ; p++)
+               {
+                   oldrow = Ai [p] ;
+                   newrow = InvRperm1 [oldrow] - n1 ;
+                   if (newrow < 0) continue ;
+                   ASSIGN (aij, Ax [p], Az [p]) ;
+                   APPROX_ABS (value, aij) ;
+                   value *= Rs [oldrow] ;
+                   weak = WEAK (value, ctol) ;
+                   if (!weak)
+                   {
+                       DEBUG0 (("    strong: row "ID": %g\n", oldrow, value)) ;
+                       Ci [pp++] = newrow ;
+                       Ri [newrow]++ ;
+                   }
+               }
+           }
+#endif
+           else
+           {
+               /* divide instead */
+               for (p = p1 ; p < p2 ; p++)
+               {
+                   oldrow = Ai [p] ;
+                   newrow = InvRperm1 [oldrow] - n1 ;
+                   if (newrow < 0) continue ;
+                   ASSIGN (aij, Ax [p], Az [p]) ;
+                   APPROX_ABS (value, aij) ;
+                   value /= Rs [oldrow] ;
+                   weak = WEAK (value, ctol) ;
+                   if (!weak)
+                   {
+                       DEBUG0 (("    strong: row "ID": %g\n", oldrow, value)) ;
+                       Ci [pp++] = newrow ;
+                       Ri [newrow]++ ;
+                   }
+               }
+           }
+       }
+    }
+    Cp [n2] = pp ;
+    ASSERT (AMD_valid (n2, n2, Cp, Ci)) ;
+
+    if (nweak == 0)
+    {
+       /* nothing to do, quick return */
+       DEBUGm2 (("\n =============================UMF_2by2: quick return\n")) ;
+       for (k = 0 ; k < n ; k++)
+       {
+           P [k] = k ;
+       }
+       *p_nweak = 0 ;
+       *p_unmatched = 0 ;
+       return ;
+    }
+
+#ifndef NDEBUG
+    for (k = 0 ; k < n2 ; k++)
+    {
+       P [k] = EMPTY ;
+    }
+    for (k = 0 ; k < n2 ; k++)
+    {
+       ASSERT (Degree [k] >= 0 && Degree [k] < n2) ;
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* find the 2-by-2 permutation */
+    /* ---------------------------------------------------------------------- */
+
+    /* The matrix S is now mapped to the index range 0 to n2-1.  We have
+     * S = A (Rperm [n1 .. n-nempty-1], Cperm [n1 .. n-nempty-1]), and then
+     * C = pattern of strong entries in S.  A weak diagonal k in S is marked
+     * with Next [k] = IS_WEAK. */
+
+    unmatched = two_by_two (n2, Cp, Ci, Degree, Next, Ri, P, Rp, Head) ;
+
+    /* ---------------------------------------------------------------------- */
+
+    *p_nweak = nweak ;
+    *p_unmatched = unmatched ;
+
+#ifndef NDEBUG
+    DEBUGm4 (("UMF_2by2: weak "ID"  unmatched "ID"\n", nweak, unmatched)) ;
+    for (row = 0 ; row < n ; row++)
+    {
+       DEBUGm2 (("P ["ID"] = "ID"\n", row, P [row])) ;
+    }
+    DEBUGm2 (("\n =============================UMF_2by2: done\n\n")) ;
+#endif
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_2by2.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_2by2.h
new file mode 100644 (file)
index 0000000..a7bb479
--- /dev/null
@@ -0,0 +1,37 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_2by2
+(
+    Int n,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const double Ax [ ],
+#ifdef COMPLEX
+    const double Az [ ],
+#endif
+    double tol,
+    Int scale,
+    Int Cperm1 [ ],
+#ifndef NDEBUG
+    Int Rperm1 [ ],
+#endif
+    Int InvRperm [ ],
+    Int n1,
+    Int nempty,
+    Int Degree [ ],
+    Int P [ ],
+    Int *p_nweak,
+    Int *p_nmatched,
+    Int Ri [ ],
+    Int Rp [ ],
+    double Rs [ ],
+    Int Head [ ],
+    Int Next [ ],
+    Int Si [ ],
+    Int Sp [ ]
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_analyze.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_analyze.c
new file mode 100644 (file)
index 0000000..b4da7e2
--- /dev/null
@@ -0,0 +1,707 @@
+/* ========================================================================== */
+/* === UMF_analyze ========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Symbolic LL' factorization of A'*A, to get upper bounds on the size of
+    L and U for LU = PAQ, and to determine the frontal matrices and
+    (supernodal) column elimination tree.  No fill-reducing column pre-ordering
+    is used.
+
+    Returns TRUE if successful, FALSE if out of memory.  UMF_analyze can only
+    run out of memory if anzmax (which is Ap [n_row]) is too small.
+
+    Uses workspace of size O(nonzeros in A).  On input, the matrix A is
+    stored in row-form at the tail end of Ai.  It is destroyed on output.
+    The rows of A must be sorted by increasing first column index.
+    The matrix is assumed to be valid.
+
+    Empty rows and columns have already been removed.
+
+*/
+
+#include "umf_internal.h"
+#include "umf_apply_order.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+#include "umf_fsize.h"
+
+/* ========================================================================== */
+
+GLOBAL Int UMF_analyze
+(
+    Int n_row,         /* A is n_row-by-n_col */
+    Int n_col,
+    Int Ai [ ],                /* Ai [Ap [0]..Ap[n_row]-1]: column indices */
+                       /* destroyed on output.  Note that this is NOT the */
+                       /* user's Ai that was passed to UMFPACK_*symbolic */
+                       /* size of Ai, Ap [n_row] = anzmax >= anz + n_col */
+                       /* Ap [0] must be => n_col.  The space to the */
+                       /* front of Ai is used as workspace. */
+
+    Int Ap [ ],                /* of size MAX (n_row, n_col) + 1 */
+                       /* Ap [0..n_row]: row pointers */
+                       /* Row i is in Ai [Ap [i] ... Ap [i+1]-1] */
+
+                       /* rows must have smallest col index first, or be */
+                       /* in sorted form.  Used as workspace of size n_col */
+                       /* and destroyed. */
+
+                       /* Note that this is NOT the */
+                       /* user's Ap that was passed to UMFPACK_*symbolic */
+
+    Int Up [ ],                /* workspace of size n_col, and output column perm.
+                        * for column etree postorder. */
+
+    Int fixQ,
+
+    /* temporary workspaces: */
+    Int W [ ],         /* W [0..n_col-1] */
+    Int Link [ ],      /* Link [0..n_col-1] */
+
+    /* output: information about each frontal matrix: */
+    Int Front_ncols [ ],       /* size n_col */
+    Int Front_nrows [ ],       /* of size n_col */
+    Int Front_npivcol [ ],     /* of size n_col */
+    Int Front_parent [ ],      /* of size n_col */
+    Int *nfr_out,
+
+    Int *p_ncompactions                /* number of compactions in UMF_analyze */
+)
+{
+    /* ====================================================================== */
+    /* ==== local variables ================================================= */
+    /* ====================================================================== */
+
+    Int j, j3, col, k, row, parent, j2, pdest, p, p2, thickness, npivots, nfr,
+       i, *Winv, kk, npiv, jnext, krow, knext, pfirst, jlast, ncompactions,
+       *Front_stack, *Front_order, *Front_child, *Front_sibling,
+       Wflag, npivcol, fallrows, fallcols, fpiv, frows, fcols, *Front_size ;
+
+    nfr = 0 ;
+    DEBUG0 (("UMF_analyze: anzmax "ID" anrow "ID" ancol "ID"\n",
+       Ap [n_row], n_row, n_col)) ;
+
+    /* ====================================================================== */
+    /* ==== initializations ================================================= */
+    /* ====================================================================== */
+
+#pragma ivdep
+    for (j = 0 ; j < n_col ; j++)
+    {
+       Link [j] = EMPTY ;
+       W [j] = EMPTY ;
+       Up [j] = EMPTY ;
+
+       /* Frontal matrix data structure: */
+       Front_npivcol [j] = 0 ;         /* number of pivot columns */
+       Front_nrows [j] = 0 ;           /* number of rows, incl. pivot rows */
+       Front_ncols [j] = 0 ;           /* number of cols, incl. pivot cols */
+       Front_parent [j] = EMPTY ;      /* parent front */
+       /* Note that only non-pivotal columns are stored in a front (a "row" */
+       /* of U) during elimination. */
+    }
+
+    /* the rows must be sorted by increasing min col */
+    krow = 0 ;
+    pfirst = Ap [0] ;
+    jlast = EMPTY ;
+    jnext = EMPTY ;
+    Wflag = 0 ;
+
+    /* this test requires the size of Ai to be >= n_col + nz */
+    ASSERT (pfirst >= n_col) ; /* Ai must be large enough */
+
+    /* pdest points to the first free space in Ai */
+    pdest = 0 ;
+    ncompactions = 0 ;
+
+    /* ====================================================================== */
+    /* === compute symbolic LL' factorization (unsorted) ==================== */
+    /* ====================================================================== */
+
+    for (j = 0 ; j < n_col ; j = jnext)
+    {
+       DEBUG1 (("\n\n============Front "ID" starting. nfr = "ID"\n", j, nfr)) ;
+
+       /* ================================================================== */
+       /* === garbage collection =========================================== */
+       /* ================================================================== */
+
+       if (pdest + (n_col-j) > pfirst)
+       {
+           /* we might run out ... compact the rows of U */
+
+#ifndef NDEBUG
+           DEBUG0 (("UMF_analyze COMPACTION, j="ID" pfirst="ID"\n",
+               j, pfirst)) ;
+           for (row = 0 ; row < j ; row++)
+           {
+               if (Up [row] != EMPTY)
+               {
+                   /* this is a live row of U */
+                   DEBUG1 (("Live row: "ID" cols: ", row)) ;
+                   p = Up [row] ;
+                   ASSERT (Front_ncols [row] > Front_npivcol [row]) ;
+                   p2 = p + (Front_ncols [row] - Front_npivcol [row]) ;
+                   for ( ; p < p2 ; p++)
+                   {
+                       DEBUG1 ((ID, Ai [p])) ;
+                       ASSERT (p < pfirst) ;
+                       ASSERT (Ai [p] > row && Ai [p] < n_col) ;
+                   }
+                   DEBUG1 (("\n")) ;
+               }
+           }
+           DEBUG1 (("\nStarting to compact:\n")) ;
+#endif
+
+           pdest = 0 ;
+           ncompactions++ ;
+           for (row = 0 ; row < j ; row++)
+           {
+               if (Up [row] != EMPTY)
+               {
+                   /* this is a live row of U */
+                   DEBUG1 (("Live row: "ID" cols: ", row)) ;
+                   ASSERT (row < n_col) ;
+                   p = Up [row] ;
+                   ASSERT (Front_ncols [row] > Front_npivcol [row]) ;
+                   p2 = p + (Front_ncols [row] - Front_npivcol [row]) ;
+                   Up [row] = pdest ;
+                   for ( ; p < p2 ; p++)
+                   {
+                       DEBUG1 ((ID, Ai [p])) ;
+                       ASSERT (p < pfirst) ;
+                       ASSERT (Ai [p] > row && Ai [p] < n_col) ;
+                       Ai [pdest++] = Ai [p] ;
+                       ASSERT (pdest <= pfirst) ;
+                   }
+                   DEBUG1 (("\n")) ;
+               }
+           }
+
+#ifndef NDEBUG
+           DEBUG1 (("\nAFTER COMPACTION, j="ID" pfirst="ID"\n", j, pfirst)) ;
+           for (row = 0 ; row < j ; row++)
+           {
+               if (Up [row] != EMPTY)
+               {
+                   /* this is a live row of U */
+                   DEBUG1 (("Live row: "ID" cols: ", row)) ;
+                   p = Up [row] ;
+                   ASSERT (Front_ncols [row] > Front_npivcol [row]) ;
+                   p2 = p + (Front_ncols [row] - Front_npivcol [row]) ;
+                   for ( ; p < p2 ; p++)
+                   {
+                       DEBUG1 ((ID, Ai [p])) ;
+                       ASSERT (p < pfirst) ;
+                       ASSERT (Ai [p] > row && Ai [p] < n_col) ;
+                   }
+                   DEBUG1 (("\n")) ;
+               }
+           }
+#endif
+
+       }
+
+       if (pdest + (n_col-j) > pfirst)
+       {
+           /* :: out of memory in umf_analyze :: */
+           /* it can't happen, if pfirst >= n_col */
+           return (FALSE) ;    /* internal error! */
+       }
+
+       /* ------------------------------------------------------------------ */
+       /* is the last front a child of this one? */
+       /* ------------------------------------------------------------------ */
+
+       if (jlast != EMPTY && Link [j] == jlast)
+       {
+           /* yes - create row j by appending to jlast */
+           DEBUG1 (("GOT:last front is child of this one: j "ID" jlast "ID"\n",
+               j, jlast)) ;
+           ASSERT (jlast >= 0 && jlast < j) ;
+
+           Up [j] = Up [jlast] ;
+           Up [jlast] = EMPTY ;
+
+           /* find the parent, delete column j, and update W */
+           parent = n_col ;
+           for (p = Up [j] ; p < pdest ; )
+           {
+               j3 = Ai [p] ;
+               DEBUG1 (("Initial row of U: col "ID" ", j3)) ;
+               ASSERT (j3 >= 0 && j3 < n_col) ;
+               DEBUG1 (("W: "ID" \n", W [j3])) ;
+               ASSERT (W [j3] == Wflag) ;
+               if (j == j3)
+               {
+                   DEBUG1 (("Found column j at p = "ID"\n", p)) ;
+                   Ai [p] = Ai [--pdest] ;
+               }
+               else
+               {
+                   if (j3 < parent)
+                   {
+                       parent = j3 ;
+                   }
+                   p++ ;
+               }
+           }
+
+           /* delete jlast from the link list of j */
+           Link [j] = Link [jlast] ;
+
+           ASSERT (Front_nrows [jlast] > Front_npivcol [jlast]) ;
+           thickness = (Front_nrows [jlast] - Front_npivcol [jlast]) ;
+           DEBUG1 (("initial thickness: "ID"\n", thickness)) ;
+
+       }
+       else
+       {
+           Up [j] = pdest ;
+           parent = n_col ;
+           /* thickness: number of (nonpivotal) rows in frontal matrix j */
+           thickness = 0 ;
+           Wflag = j ;
+       }
+
+       /* ================================================================== */
+       /* === compute row j of A*A' ======================================== */
+       /* ================================================================== */
+
+       /* ------------------------------------------------------------------ */
+       /* flag the diagonal entry in row U, but do not add to pattern */
+       /* ------------------------------------------------------------------ */
+
+       ASSERT (pdest <= pfirst) ;
+       W [j] = Wflag ;
+
+       DEBUG1 (("\nComputing row "ID" of A'*A\n", j)) ;
+       DEBUG2 (("      col: "ID" (diagonal)\n", j)) ;
+
+       /* ------------------------------------------------------------------ */
+       /* find the rows the contribute to this column j */
+       /* ------------------------------------------------------------------ */
+
+       jnext = n_col ;
+       for (knext = krow ; knext < n_row ; knext++)
+       {
+           ASSERT (Ap [knext] < Ap [knext+1]) ;
+           ASSERT (Ap [knext] >= pfirst && Ap [knext] <= Ap [n_row]) ;
+           jnext = Ai [Ap [knext]] ;
+           ASSERT (jnext >= j) ;
+           if (jnext != j)
+           {
+               break ;
+           }
+       }
+
+       /* rows krow ... knext-1 all have first column index of j */
+       /* (or are empty) */
+
+       /* row knext has first column index of jnext */
+       /* if knext = n_row, then jnext is n_col */
+       if (knext == n_row)
+       {
+           jnext = n_col ;
+       }
+
+       ASSERT (jnext > j) ;
+       ASSERT (jnext <= n_col) ;
+
+       /* ------------------------------------------------------------------ */
+       /* for each nonzero A (k,j) in column j of A do: */
+       /* ------------------------------------------------------------------ */
+
+       for (k = krow ; k < knext ; k++)
+       {
+           p = Ap [k] ;
+           p2 = Ap [k+1] ;
+           ASSERT (p < p2) ;
+
+           /* merge row k of A into W */
+           DEBUG2 (("  ---- A row "ID" ", k)) ;
+           ASSERT (k >= 0 && k < n_row) ;
+           ASSERT (Ai [p] == j) ;
+           DEBUG2 (("  p "ID" p2 "ID"\n        cols:", p, p2)) ;
+           ASSERT (p  >= pfirst && p  < Ap [n_row]) ;
+           ASSERT (p2 >  pfirst && p2 <= Ap [n_row]) ;
+           for ( ; p < p2 ; p++)
+           {
+               /* add to pattern if seen for the first time */
+               col = Ai [p] ;
+               ASSERT (col >= j && col < n_col) ;
+               DEBUG3 ((" "ID, col)) ;
+               if (W [col] != Wflag)
+               {
+                   Ai [pdest++] = col ;
+                   ASSERT (pdest <= pfirst) ;
+                   /* flag this column has having been seen for row j */
+                   W [col] = Wflag ;
+                   if (col < parent)
+                   {
+                       parent = col ;
+                   }
+               }
+           }
+           DEBUG2 (("\n")) ;
+           thickness++ ;
+       }
+
+#ifndef NDEBUG
+       DEBUG3 (("\nRow "ID" of A'A:\n", j)) ;
+       for (p = Up [j] ; p < pdest ; p++)
+       {
+           DEBUG3 ((" "ID, Ai [p])) ;
+       }
+       DEBUG3 (("\n")) ;
+#endif
+
+       /* ------------------------------------------------------------------ */
+       /* delete rows up to but not including knext */
+       /* ------------------------------------------------------------------ */
+
+       krow = knext ;
+       pfirst = Ap [knext] ;
+
+       /* we can now use Ai [0..pfirst-1] as workspace for rows of U */
+
+       /* ================================================================== */
+       /* === compute jth row of U ========================================= */
+       /* ================================================================== */
+
+       /* for each nonzero U (k,j) in column j of U (1:j-1,:) do */
+       for (k = Link [j] ; k != EMPTY ; k = Link [k])
+       {
+           /* merge row k of U into W */
+           DEBUG2 (("  ---- U row "ID, k)) ;
+           ASSERT (k >= 0 && k < n_col) ;
+           ASSERT (Up [k] != EMPTY) ;
+           p = Up [k] ;
+           ASSERT (Front_ncols [k] > Front_npivcol [k]) ;
+           p2 = p + (Front_ncols [k] - Front_npivcol [k]) ;
+           DEBUG2 (("  p "ID" p2 "ID"\n        cols:", p, p2)) ;
+           ASSERT (p <= pfirst) ;
+           ASSERT (p2 <= pfirst) ;
+           for ( ; p < p2 ; p++)
+           {
+               /* add to pattern if seen for the first time */
+               col = Ai [p] ;
+               ASSERT (col >= j && col < n_col) ;
+               DEBUG3 ((" "ID, col)) ;
+               if (W [col] != Wflag)
+               {
+                   Ai [pdest++] = col ;
+                   ASSERT (pdest <= pfirst) ;
+                   /* flag this col has having been seen for row j */
+                   W [col] = Wflag ;
+                   if (col < parent)
+                   {
+                       parent = col ;
+                   }
+               }
+           }
+           DEBUG2 (("\n")) ;
+
+           /* mark the row k as deleted */
+           Up [k] = EMPTY ;
+
+           ASSERT (Front_nrows [k] > Front_npivcol [k]) ;
+           thickness += (Front_nrows [k] - Front_npivcol [k]) ;
+           ASSERT (Front_parent [k] == j) ;
+       }
+
+#ifndef NDEBUG
+       DEBUG3 (("\nRow "ID" of U prior to supercolumn detection:\n", j));
+       for (p = Up [j] ; p < pdest ; p++)
+       {
+           DEBUG3 ((" "ID, Ai [p])) ;
+       }
+       DEBUG3 (("\n")) ;
+       DEBUG1 (("thickness, prior to supercol detect: "ID"\n", thickness)) ;
+#endif
+
+       /* ================================================================== */
+       /* === quicky mass elimination ====================================== */
+       /* ================================================================== */
+
+       /* this code detects some supernodes, but it might miss */
+       /* some because the elimination tree (created on the fly) */
+       /* is not yet post-ordered, and because the pattern of A'*A */
+       /* is also computed on the fly. */
+
+       /* j2 is incremented because the pivot columns are not stored */
+
+       for (j2 = j+1 ; j2 < jnext ; j2++)
+       {
+           ASSERT (j2 >= 0 && j2 < n_col) ;
+           if (W [j2] != Wflag || Link [j2] != EMPTY)
+           {
+               break ;
+           }
+       }
+
+       /* the loop above terminated with j2 at the first non-supernode */
+       DEBUG1 (("jnext = "ID"\n", jnext)) ;
+       ASSERT (j2 <= jnext) ;
+       jnext = j2 ;
+       j2-- ;
+       DEBUG1 (("j2 = "ID"\n", j2)) ;
+       ASSERT (j2 < n_col) ;
+
+       npivots = j2-j+1 ;
+       DEBUG1 (("Number of pivot columns: "ID"\n", npivots)) ;
+
+       /* rows j:j2 have the same nonzero pattern, except for columns j:j2-1 */
+
+       if (j2 > j)
+       {
+           /* supernode detected, prune the pattern of new row j */
+           ASSERT (parent == j+1) ;
+           ASSERT (j2 < n_col) ;
+           DEBUG1 (("Supernode detected, j "ID" to j2 "ID"\n", j, j2)) ;
+
+           parent = n_col ;
+           p2 = pdest ;
+           pdest = Up [j] ;
+           for (p = Up [j] ; p < p2 ; p++)
+           {
+               col = Ai [p] ;
+               ASSERT (col >= 0 && col < n_col) ;
+               ASSERT (W [col] == Wflag) ;
+               if (col > j2)
+               {
+                   /* keep this col in the pattern of the new row j */
+                   Ai [pdest++] = col ;
+                   if (col < parent)
+                   {
+                       parent = col ;
+                   }
+               }
+           }
+       }
+
+       DEBUG1 (("Parent ["ID"] = "ID"\n", j, parent)) ;
+       ASSERT (parent > j2) ;
+
+       if (parent == n_col)
+       {
+           /* this front has no parent - it is the root of a subtree */
+           parent = EMPTY ;
+       }
+
+#ifndef NDEBUG
+       DEBUG3 (("\nFinal row "ID" of U after supercolumn detection:\n", j)) ;
+       for (p = Up [j] ; p < pdest ; p++)
+       {
+           ASSERT (Ai [p] >= 0 && Ai [p] < n_col) ;
+           DEBUG3 ((" "ID" ("ID")", Ai [p], W [Ai [p]])) ;
+           ASSERT (W [Ai [p]] == Wflag) ;
+       }
+       DEBUG3 (("\n")) ;
+#endif
+
+       /* ================================================================== */
+       /* === frontal matrix =============================================== */
+       /* ================================================================== */
+
+       /* front has Front_npivcol [j] pivot columns */
+       /* entire front is Front_nrows [j] -by- Front_ncols [j] */
+       /* j is first column in the front */
+
+       npivcol = npivots ;
+       fallrows = thickness ;
+       fallcols = npivots + pdest - Up [j] ;
+
+       /* number of pivots in the front (rows and columns) */
+       fpiv = MIN (npivcol, fallrows) ;
+
+       /* size of contribution block */
+       frows = fallrows - fpiv ;
+       fcols = fallcols - fpiv ;
+
+       if (frows == 0 || fcols == 0)
+       {
+           /* front has no contribution block and thus needs no parent */
+           DEBUG1 (("Frontal matrix evaporation\n")) ;
+           Up [j] = EMPTY ;
+           parent = EMPTY ;
+       }
+
+       Front_npivcol [j] = npivots ;
+       Front_nrows [j] = fallrows ;
+       Front_ncols [j] = fallcols ;
+       Front_parent [j] = parent ;
+       ASSERT (npivots > 0) ;
+
+       /* Front_parent [j] is the first column of the parent frontal matrix */
+
+       DEBUG1 (("\n\n==== Front "ID", nfr "ID" pivot columns "ID":"ID
+           " all front: "ID"-by-"ID" Parent: "ID"\n", j, nfr, j,j+npivots-1,
+           Front_nrows [j], Front_ncols [j], Front_parent [j])) ;
+       nfr++ ;
+
+       /* ================================================================== */
+       /* === prepare this row for its parent ============================== */
+       /* ================================================================== */
+
+       if (parent != EMPTY)
+       {
+           Link [j] = Link [parent] ;
+           Link [parent] = j ;
+       }
+
+       ASSERT (jnext > j) ;
+
+       jlast = j ;
+    }
+
+    /* ====================================================================== */
+    /* === postorder the fronts ============================================= */
+    /* ====================================================================== */
+
+    *nfr_out = nfr ;
+
+    Front_order = W ;  /* use W for Front_order [ */
+
+    if (fixQ)
+    {
+       /* do not postorder the fronts if Q is fixed */
+       DEBUG1 (("\nNo postorder (Q is fixed)\n")) ;
+       k = 0 ;
+       /* 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/deal.II/contrib/umfpack/UMFPACK/Source/umf_analyze.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_analyze.h
new file mode 100644 (file)
index 0000000..cb3af8a
--- /dev/null
@@ -0,0 +1,24 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_analyze
+(
+    Int n_row,
+    Int n_col,
+    Int Ai [ ],
+    Int Ap [ ],
+    Int Up [ ],
+    Int fixQ,
+    Int Front_ncols [ ],
+    Int W [ ],
+    Int Link [ ],
+    Int Front_nrows [ ],
+    Int Front_npivcol [ ],
+    Int Front_parent [ ],
+    Int *nfr_out,
+    Int *p_ncompactions
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_apply_order.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_apply_order.c
new file mode 100644 (file)
index 0000000..88e9b62
--- /dev/null
@@ -0,0 +1,44 @@
+/* ========================================================================== */
+/* === UMF_apply_order ====================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Apply post-ordering of supernodal elimination tree.
+*/
+
+#include "umf_internal.h"
+
+GLOBAL void UMF_apply_order
+(
+    Int Front [ ],         /* of size nn on input, size nfr on output */
+    const Int Order [ ],    /* Order [i] = k, i in the range 0..nn-1,
+                            * and k in the range 0..nfr-1, means that node
+                            * i is the kth node in the postordered tree. */
+    Int Temp [ ],          /* workspace of size nfr */
+    Int nn,                /* nodes are numbered in the range 0..nn-1 */
+    Int nfr                /* the number of nodes actually in use */
+)
+{
+    Int i, k ;
+    for (i = 0 ; i < nn ; i++)
+    {
+       k = Order [i] ;
+       ASSERT (k >= EMPTY && k < nfr) ;
+       if (k != EMPTY)
+       {
+           Temp [k] = Front [i] ;
+       }
+    }
+
+    for (k = 0 ; k < nfr ; k++)
+    {
+       Front [k] = Temp [k] ;
+    }
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_apply_order.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_apply_order.h
new file mode 100644 (file)
index 0000000..73b63a6
--- /dev/null
@@ -0,0 +1,15 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_apply_order
+(
+    Int Front [ ],
+    const Int Order [ ],
+    Int Temp [ ],
+    Int n_col,
+    Int nfr
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_assemble.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_assemble.c
new file mode 100644 (file)
index 0000000..1e1b0f2
--- /dev/null
@@ -0,0 +1,1216 @@
+/* ========================================================================== */
+/* === UMF_assemble ========================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*  Degree update and numerical assembly.  This is compiled twice (with and
+ *  without FIXQ) for each real/complex int/long version, for a total of 8
+ *  versions.*/
+
+#include "umf_internal.h"
+#include "umf_mem_free_tail_block.h"
+
+/* ========================================================================== */
+/* === row_assemble ========================================================= */
+/* ========================================================================== */
+
+PRIVATE void row_assemble
+(
+    Int row,
+    NumericType *Numeric,
+    WorkType *Work
+)
+{
+
+    Int tpi, e, *E, *Fcpos, *Frpos, *Row_degree, *Row_tuples, *Row_tlen, rdeg0,
+       f, nrows, ncols, *Rows, *Cols, col, ncolsleft, j ;
+    Tuple *tp, *tp1, *tp2, *tpend ;
+    Unit *Memory, *p ;
+    Element *ep ;
+    Entry *S, *Fcblock, *Frow ;
+
+#ifndef FIXQ
+    Int *Col_degree ;
+    Col_degree = Numeric->Cperm ;
+#endif
+
+    Row_tuples = Numeric->Uip ;
+    tpi = Row_tuples [row] ;
+    if (!tpi) return ;
+
+    Memory = Numeric->Memory ;
+    E = Work->E ;
+    Fcpos = Work->Fcpos ;
+    Frpos = Work->Frpos ;
+    Row_degree = Numeric->Rperm ;
+    Row_tlen   = Numeric->Uilen ;
+    E = Work->E ;
+    Memory = Numeric->Memory ;
+    rdeg0 = Work->rdeg0 ;
+    Fcblock = Work->Fcblock ;
+
+#ifndef NDEBUG
+    DEBUG6 (("SCAN2-row: "ID"\n", row)) ;
+    UMF_dump_rowcol (0, Numeric, Work, row, FALSE) ;
+#endif
+
+    ASSERT (NON_PIVOTAL_ROW (row)) ;
+
+    tp = (Tuple *) (Memory + tpi) ;
+    tp1 = tp ;
+    tp2 = tp ;
+    tpend = tp + Row_tlen [row] ;
+    for ( ; tp < tpend ; tp++)
+    {
+       e = tp->e ;
+       ASSERT (e > 0 && e <= Work->nel) ;
+       if (!E [e]) continue ;  /* element already deallocated */
+       f = tp->f ;
+       p = Memory + E [e] ;
+       ep = (Element *) p ;
+       p += UNITS (Element, 1) ;
+       Cols = (Int *) p ;
+       Rows = Cols + ep->ncols ;
+       if (Rows [f] == EMPTY) continue ;   /* row already assembled */
+       ASSERT (row == Rows [f] && row >= 0 && row < Work->n_row) ;
+
+       if (ep->rdeg == rdeg0)
+       {
+           /* ------------------------------------------------------ */
+           /* this is an old Lson - assemble just one row */
+           /* ------------------------------------------------------ */
+
+           /* flag the row as assembled from the Lson */
+           Rows [f] = EMPTY ;
+
+           nrows = ep->nrows ;
+           ncols = ep->ncols ;
+
+           p += UNITS (Int, ncols + nrows) ;
+           S = ((Entry *) p) + f ;
+
+           DEBUG6 (("Old LSON: "ID"\n", e)) ;
+#ifndef NDEBUG
+           UMF_dump_element (Numeric, Work, e, FALSE) ;
+#endif
+
+           ncolsleft = ep->ncolsleft ;
+
+           Frow = Fcblock + Frpos [row] ;
+           DEBUG6 (("LSON found (in scan2-row): "ID"\n", e)) ;
+
+           Row_degree [row] -= ncolsleft ;
+
+           if (ncols == ncolsleft)
+           {
+               /* -------------------------------------------------- */
+               /* no columns assembled out this Lson yet */
+               /* -------------------------------------------------- */
+
+#pragma ivdep
+               for (j = 0 ; j < ncols ; j++)
+               {
+                   col = Cols [j] ;
+                   ASSERT (col >= 0 && col < Work->n_col) ;
+#ifndef FIXQ
+                   Col_degree [col] -- ;
+#endif
+                   /* Frow [Fcpos [col]] += *S ; */
+                   ASSEMBLE (Frow [Fcpos [col]], *S) ;
+                   S += nrows ;
+               }
+
+           }
+           else
+           {
+               /* -------------------------------------------------- */
+               /* some columns have been assembled out of this Lson */
+               /* -------------------------------------------------- */
+
+#pragma ivdep
+               for (j = 0 ; j < ncols ; j++)
+               {
+                   col = Cols [j] ;
+                   if (col >= 0)
+                   {
+                       ASSERT (col < Work->n_col) ;
+#ifndef FIXQ
+                       Col_degree [col] -- ;
+#endif
+                       /* Frow [Fcpos [col]] += *S ; */
+                       ASSEMBLE (Frow [Fcpos [col]], *S) ;
+                   }
+                   S += nrows ;
+               }
+
+           }
+           ep->nrowsleft-- ;
+           ASSERT (ep->nrowsleft > 0) ;
+       }
+       else
+       {
+           *tp2++ = *tp ;      /* leave the tuple in the list */
+       }
+    }
+    Row_tlen [row] = tp2 - tp1 ;
+
+#ifndef NDEBUG
+    DEBUG7 (("row assembled in scan2-row: "ID"\n", row)) ;
+    UMF_dump_rowcol (0, Numeric, Work, row, FALSE) ;
+    DEBUG7 (("Current frontal matrix: (scan 1b)\n")) ;
+    UMF_dump_current_front (Numeric, Work, TRUE) ;
+#endif
+}
+
+/* ========================================================================== */
+/* === col_assemble ========================================================= */
+/* ========================================================================== */
+
+PRIVATE void col_assemble
+(
+    Int col,
+    NumericType *Numeric,
+    WorkType *Work
+)
+{
+
+    Int tpi, e, *E, *Fcpos, *Frpos, *Row_degree, *Col_tuples, *Col_tlen, cdeg0,
+       f, nrows, ncols, *Rows, *Cols, row, nrowsleft, i ;
+    Tuple *tp, *tp1, *tp2, *tpend ;
+    Unit *Memory, *p ;
+    Element *ep ;
+    Entry *S, *Fcblock, *Fcol ;
+
+#if !defined (FIXQ) || !defined (NDEBUG)
+    Int *Col_degree ;
+    Col_degree = Numeric->Cperm ;
+#endif
+
+    Col_tuples = Numeric->Lip ;
+    tpi = Col_tuples [col] ;
+    if (!tpi) return ;
+
+    Memory = Numeric->Memory ;
+    E = Work->E ;
+    Fcpos = Work->Fcpos ;
+    Frpos = Work->Frpos ;
+    Row_degree = Numeric->Rperm ;
+    Col_tlen   = Numeric->Lilen ;
+    E = Work->E ;
+    Memory = Numeric->Memory ;
+    cdeg0 = Work->cdeg0 ;
+    Fcblock = Work->Fcblock ;
+
+    DEBUG6 (("SCAN2-col: "ID"\n", col)) ;
+#ifndef NDEBUG
+    UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ;
+#endif
+
+    ASSERT (NON_PIVOTAL_COL (col)) ;
+    tp = (Tuple *) (Memory + tpi) ;
+    tp1 = tp ;
+    tp2 = tp ;
+    tpend = tp + Col_tlen [col] ;
+    for ( ; tp < tpend ; tp++)
+    {
+       e = tp->e ;
+       ASSERT (e > 0 && e <= Work->nel) ;
+       if (!E [e]) continue ;  /* element already deallocated */
+       f = tp->f ;
+       p = Memory + E [e] ;
+       ep = (Element *) p ;
+       p += UNITS (Element, 1) ;
+       Cols = (Int *) p ;
+
+       if (Cols [f] == EMPTY) continue ;   /* col already assembled */
+       ASSERT (col == Cols [f] && col >= 0 && col < Work->n_col) ;
+
+       if (ep->cdeg == cdeg0)
+       {
+           /* ------------------------------------------------------ */
+           /* this is an old Uson - assemble just one col */
+           /* ------------------------------------------------------ */
+
+           /* flag the col as assembled from the Uson */
+           Cols [f] = EMPTY ;
+
+           nrows = ep->nrows ;
+           ncols = ep->ncols ;
+           Rows = Cols + ncols ;
+           p += UNITS (Int, ncols + nrows) ;
+           S = ((Entry *) p) + f * nrows ;
+
+           DEBUG6 (("Old USON: "ID"\n", e)) ;
+#ifndef NDEBUG
+           UMF_dump_element (Numeric, Work, e, FALSE) ;
+#endif
+
+           nrowsleft = ep->nrowsleft ;
+
+           Fcol = Fcblock + Fcpos [col] ;
+           DEBUG6 (("USON found (in scan2-col): "ID"\n", e)) ;
+#ifndef FIXQ
+           Col_degree [col] -= nrowsleft ;
+#endif
+           if (nrows == nrowsleft)
+           {
+               /* -------------------------------------------------- */
+               /* no rows assembled out of this Uson yet */
+               /* -------------------------------------------------- */
+
+#pragma ivdep
+               for (i = 0 ; i < nrows ; i++)
+               {
+                   row = Rows [i] ;
+                   ASSERT (row >= 0 && row < Work->n_row) ;
+                   Row_degree [row]-- ;
+                   /* Fcol [Frpos [row]] += S [i] ; */
+                   ASSEMBLE (Fcol [Frpos [row]], S [i]) ;
+               }
+           }
+           else
+           {
+               /* -------------------------------------------------- */
+               /* some rows have been assembled out of this Uson */
+               /* -------------------------------------------------- */
+
+#pragma ivdep
+               for (i = 0 ; i < nrows ; i++)
+               {
+                   row = Rows [i] ;
+                   if (row >= 0)
+                   {
+                       ASSERT (row < Work->n_row) ;
+                       Row_degree [row]-- ;
+                       /* Fcol [Frpos [row]] += S [i] ; */
+                       ASSEMBLE (Fcol [Frpos [row]], S [i]) ;
+                   }
+               }
+           }
+           ep->ncolsleft-- ;
+           ASSERT (ep->ncolsleft > 0) ;
+       }
+       else
+       {
+           *tp2++ = *tp ;      /* leave the tuple in the list */
+       }
+    }
+    Col_tlen [col] = tp2 - tp1 ;
+
+#ifndef NDEBUG
+    DEBUG7 (("Column assembled in scan2-col: "ID"\n", col)) ;
+    UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ;
+    DEBUG7 (("Current frontal matrix: after scan2-col\n")) ;
+    UMF_dump_current_front (Numeric, Work, TRUE) ;
+#endif
+
+}
+
+
+/* ========================================================================== */
+/* === UMF_assemble / UMF_assemble_fixq ===================================== */
+/* ========================================================================== */
+
+#ifndef FIXQ
+GLOBAL void UMF_assemble
+#else
+GLOBAL void UMF_assemble_fixq
+#endif
+(
+    NumericType *Numeric,
+    WorkType *Work
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int e, i, row, col, i2, nrows, ncols, f, tpi, extcdeg, extrdeg, rdeg0,
+       cdeg0, son_list, next, nrows_to_assemble,
+       ncols_to_assemble, ngetrows, j, j2,
+       nrowsleft,      /* number of rows remaining in S */
+       ncolsleft,      /* number of columns remaining in S */
+       prior_Lson, prior_Uson, *E, *Cols, *Rows, *Wm, *Woo,
+       *Row_tuples, *Row_degree, *Row_tlen,
+       *Col_tuples, *Col_tlen ;
+    Unit *Memory, *p ;
+    Element *ep ;
+    Tuple *tp, *tp1, *tp2, *tpend ;
+    Entry
+       *S,             /* a pointer into the contribution block of a son */
+       *Fcblock,       /* current contribution block */
+       *Fcol ;         /* a column of FC */
+    Int *Frpos,
+       *Fcpos,
+       fnrows,         /* number of rows in contribution block in F */
+       fncols ;        /* number of columns in contribution block in F */
+
+#if !defined (FIXQ) || !defined (NDEBUG)
+    Int *Col_degree ;
+#endif
+
+#ifndef NDEBUG
+    Int n_row, n_col ;
+    n_row = Work->n_row ;
+    n_col = Work->n_col ;
+    DEBUG3 (("::Assemble SCANS 1-4\n")) ;
+    UMF_dump_current_front (Numeric, Work, TRUE) ;
+#endif
+
+#if !defined (FIXQ) || !defined (NDEBUG)
+    Col_degree = Numeric->Cperm ;   /* not updated if FIXQ is true */
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    fncols = Work->fncols ;
+    fnrows = Work->fnrows ;
+    Fcpos = Work->Fcpos ;
+    Frpos = Work->Frpos ;
+    Row_degree = Numeric->Rperm ;
+    Row_tuples = Numeric->Uip ;
+    Row_tlen   = Numeric->Uilen ;
+    Col_tuples = Numeric->Lip ;
+    Col_tlen   = Numeric->Lilen ;
+    E = Work->E ;
+    Memory = Numeric->Memory ;
+    Wm = Work->Wm ;
+    Woo = Work->Woo ;
+    rdeg0 = Work->rdeg0 ;
+    cdeg0 = Work->cdeg0 ;
+
+#ifndef NDEBUG
+    DEBUG6 (("============================================\n")) ;
+    DEBUG6 (("Degree update, assembly.\n")) ;
+    DEBUG6 (("pivot row pattern:  fncols="ID"\n", fncols)) ;
+    for (j = 0 ; j < fncols ; j++)
+    {
+       col = Work->Fcols [j] ;
+       DEBUG6 ((ID" ", col)) ;
+       ASSERT (Fcpos [col] == j * Work->fnr_curr) ;
+       ASSERT (NON_PIVOTAL_COL (col)) ;
+    }
+    ASSERT (Fcpos [Work->pivcol] >= 0) ;
+    DEBUG6 (("pivcol: "ID" pos "ID" fnr_curr "ID" fncols "ID"\n",
+       Work->pivcol, Fcpos [Work->pivcol], Work->fnr_curr, fncols)) ;
+    ASSERT (Fcpos [Work->pivcol] <  fncols * Work->fnr_curr) ;
+    DEBUG6 (("\npivot col pattern:  fnrows="ID"\n", fnrows)) ;
+    for (i = 0 ; i < fnrows ; i++)
+    {
+       row = Work->Frows [i] ;
+       DEBUG6 ((ID" ", row)) ;
+       ASSERT (Frpos [row] == i) ;
+       ASSERT (NON_PIVOTAL_ROW (row)) ;
+    }
+    DEBUG6 (("\n")) ;
+    ASSERT (Frpos [Work->pivrow] >= 0) ;
+    ASSERT (Frpos [Work->pivrow] < fnrows) ;
+    ASSERT (Work->Flublock == (Entry *) (Numeric->Memory + E [0])) ;
+    ASSERT (Work->Fcblock == Work->Flublock + Work->nb *
+       (Work->nb + Work->fnr_curr + Work->fnc_curr)) ;
+#endif
+
+    Fcblock = Work->Fcblock ;
+
+    /* ---------------------------------------------------------------------- */
+    /* determine the largest actual frontal matrix size (for Info only) */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (fnrows == Work->fnrows_new + 1) ;
+    ASSERT (fncols == Work->fncols_new + 1) ;
+
+    Numeric->maxnrows = MAX (Numeric->maxnrows, fnrows) ;
+    Numeric->maxncols = MAX (Numeric->maxncols, fncols) ;
+
+    /* this is safe from integer overflow, since the current frontal matrix
+     * is already allocated. */
+    Numeric->maxfrsize = MAX (Numeric->maxfrsize, fnrows * fncols) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* assemble from prior elements into the current frontal matrix */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG2 (("New assemble start [prior_element:"ID"\n", Work->prior_element)) ;
+
+    /* Currently no rows or columns are marked.  No elements are scanned, */
+    /* that is, (ep->next == EMPTY) is true for all elements */
+
+    son_list = 0 ;     /* start creating son_list [ */
+
+    /* ---------------------------------------------------------------------- */
+    /* determine if most recent element is Lson or Uson of current front */
+    /* ---------------------------------------------------------------------- */
+
+    if (!Work->do_extend)
+    {
+       prior_Uson = ( Work->pivcol_in_front && !Work->pivrow_in_front) ;
+       prior_Lson = (!Work->pivcol_in_front &&  Work->pivrow_in_front) ;
+       if (prior_Uson || prior_Lson)
+       {
+           e = Work->prior_element ;
+           if (e != EMPTY)
+           {
+               ASSERT (E [e]) ;
+               p = Memory + E [e] ;
+               ep = (Element *) p ;
+               ep->next = son_list ;
+               son_list = e ;
+#ifndef NDEBUG
+               DEBUG2 (("e "ID" is Prior son "ID" "ID"\n",
+                   e, prior_Uson, prior_Lson)) ;
+               UMF_dump_element (Numeric, Work, e, FALSE) ;
+#endif
+               ASSERT (E [e]) ;
+           }
+       }
+    }
+    Work->prior_element = EMPTY ;
+
+    /* ---------------------------------------------------------------------- */
+    /* SCAN1-row:  scan the element lists of each new row in the pivot col */
+    /* and compute the external column degree for each frontal */
+    /* ---------------------------------------------------------------------- */
+
+    for (i2 = Work->fscan_row ; i2 < fnrows ; i2++)
+    {
+       /* Get a row */
+       row = Work->NewRows [i2] ;
+       if (row < 0) row = FLIP (row) ;
+       ASSERT (row >= 0 && row < n_row) ;
+
+       DEBUG6 (("SCAN1-row: "ID"\n", row)) ;
+#ifndef NDEBUG
+       UMF_dump_rowcol (0, Numeric, Work, row, FALSE) ;
+#endif
+
+       ASSERT (NON_PIVOTAL_ROW (row)) ;
+       tpi = Row_tuples [row] ;
+       if (!tpi) continue ;
+       tp = (Tuple *) (Memory + tpi) ;
+       tp1 = tp ;
+       tp2 = tp ;
+       tpend = tp + Row_tlen [row] ;
+       for ( ; tp < tpend ; tp++)
+       {
+           e = tp->e ;
+           ASSERT (e > 0 && e <= Work->nel) ;
+           if (!E [e]) continue ;      /* element already deallocated */
+           f = tp->f ;
+           p = Memory + E [e] ;
+           ep = (Element *) p ;
+           p += UNITS (Element, 1) ;
+           Rows = ((Int *) p) + ep->ncols ;
+           if (Rows [f] == EMPTY) continue ;   /* row already assembled */
+           ASSERT (row == Rows [f]) ;
+
+           if (ep->cdeg < cdeg0)
+           {
+               /* first time seen in scan1-row */
+               ep->cdeg = ep->nrowsleft + cdeg0 ;
+               DEBUG6 (("e "ID" First seen: cdeg: "ID" ", e, ep->cdeg-cdeg0)) ;
+               ASSERT (ep->ncolsleft > 0 && ep->nrowsleft > 0) ;
+           }
+
+           ep->cdeg-- ;        /* decrement external column degree */
+           DEBUG6 (("e "ID" New ext col deg: "ID"\n", e, ep->cdeg - cdeg0)) ;
+
+           /* this element is not yet in the new son list */
+           if (ep->cdeg == cdeg0 && ep->next == EMPTY)
+           {
+               /* A new LUson or Uson has been found */
+               ep->next = son_list ;
+               son_list = e ;
+           }
+
+           ASSERT (ep->cdeg >= cdeg0) ;
+           *tp2++ = *tp ;      /* leave the tuple in the list */
+       }
+       Row_tlen [row] = tp2 - tp1 ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* SCAN1-col:  scan the element lists of each new col in the pivot row */
+    /*  and compute the external row degree for each frontal */
+    /* ---------------------------------------------------------------------- */
+
+    for (j2 = Work->fscan_col ; j2 < fncols ; j2++)
+    {
+       /* Get a column */
+       col = Work->NewCols [j2] ;
+       if (col < 0) col = FLIP (col) ;
+       ASSERT (col >= 0 && col < n_col) ;
+
+       DEBUG6 (("SCAN 1-col: "ID"\n", col)) ;
+#ifndef NDEBUG
+       UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ;
+#endif
+
+       ASSERT (NON_PIVOTAL_COL (col)) ;
+       tpi = Col_tuples [col] ;
+       if (!tpi) continue ;
+       tp = (Tuple *) (Memory + tpi) ;
+       tp1 = tp ;
+       tp2 = tp ;
+       tpend = tp + Col_tlen [col] ;
+       for ( ; tp < tpend ; tp++)
+       {
+           e = tp->e ;
+           ASSERT (e > 0 && e <= Work->nel) ;
+           if (!E [e]) continue ;      /* element already deallocated */
+           f = tp->f ;
+           p = Memory + E [e] ;
+           ep = (Element *) p ;
+           p += UNITS (Element, 1) ;
+           Cols = (Int *) p ;
+           if (Cols [f] == EMPTY) continue ;   /* column already assembled */
+           ASSERT (col == Cols [f]) ;
+
+           if (ep->rdeg < rdeg0)
+           {
+               /* first time seen in scan1-col */
+               ep->rdeg = ep->ncolsleft + rdeg0 ;
+               DEBUG6 (("e "ID" First seen: rdeg: "ID" ", e, ep->rdeg-rdeg0)) ;
+               ASSERT (ep->ncolsleft > 0 && ep->nrowsleft > 0) ;
+           }
+
+           ep->rdeg-- ;        /* decrement external row degree */
+           DEBUG6 (("e "ID" New ext row degree: "ID"\n", e, ep->rdeg-rdeg0)) ;
+
+           if (ep->rdeg == rdeg0 && ep->next == EMPTY)
+           {
+               /* A new LUson or Lson has been found */
+               ep->next = son_list ;
+               son_list = e ;
+           }
+
+           ASSERT (ep->rdeg >= rdeg0) ;
+           *tp2++ = *tp ;      /* leave the tuple in the list */
+       }
+       Col_tlen [col] = tp2 - tp1 ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* assemble new sons via full scans */
+    /* ---------------------------------------------------------------------- */
+
+    next = EMPTY ;
+
+    for (e = son_list ; e > 0 ; e = next)
+    {
+       ASSERT (e > 0 && e <= Work->nel && E [e]) ;
+       p = Memory + E [e] ;
+       DEBUG2 (("New son: "ID"\n", e)) ;
+#ifndef NDEBUG
+       UMF_dump_element (Numeric, Work, e, FALSE) ;
+#endif
+       GET_ELEMENT (ep, p, Cols, Rows, ncols, nrows, S) ;
+       nrowsleft = ep->nrowsleft ;
+       ncolsleft = ep->ncolsleft ;
+       next = ep->next ;
+       ep->next = EMPTY ;
+
+       extrdeg = (ep->rdeg < rdeg0) ? ncolsleft : (ep->rdeg - rdeg0) ;
+       extcdeg = (ep->cdeg < cdeg0) ? nrowsleft : (ep->cdeg - cdeg0) ;
+       ncols_to_assemble = ncolsleft - extrdeg ;
+       nrows_to_assemble = nrowsleft - extcdeg ;
+       DEBUG2 (("extrdeg "ID" extcdeg "ID"\n", extrdeg, extcdeg)) ;
+
+       if (extrdeg == 0 && extcdeg == 0)
+       {
+
+           /* -------------------------------------------------------------- */
+           /* this is an LUson - assemble an entire contribution block */
+           /* -------------------------------------------------------------- */
+
+           DEBUG6 (("LUson found: "ID"\n", e)) ;
+
+           if (nrows == nrowsleft)
+           {
+               /* ---------------------------------------------------------- */
+               /* no rows assembled out of this LUson yet */
+               /* ---------------------------------------------------------- */
+
+               /* compute the compressed column offset vector*/
+               /* [ use Wm [0..nrows-1] for offsets */
+#pragma ivdep
+               for (i = 0 ; i < nrows ; i++)
+               {
+                   row = Rows [i] ;
+                   Row_degree [row] -= ncolsleft ;
+                   Wm [i] = Frpos [row] ;
+               }
+
+               if (ncols == ncolsleft)
+               {
+                   /* ------------------------------------------------------ */
+                   /* no rows or cols assembled out of LUson yet */
+                   /* ------------------------------------------------------ */
+
+                   for (j = 0 ; j < ncols ; j++)
+                   {
+                       col = Cols [j] ;
+#ifndef FIXQ
+                       Col_degree [col] -= nrowsleft ;
+#endif
+                       Fcol = Fcblock + Fcpos [col] ;
+#pragma ivdep
+                       for (i = 0 ; i < nrows ; i++)
+                       {
+                           /* Fcol [Wm [i]] += S [i] ; */
+                           ASSEMBLE (Fcol [Wm [i]], S [i]) ;
+                       }
+                       S += nrows ;
+                   }
+
+
+               }
+               else
+               {
+                   /* ------------------------------------------------------ */
+                   /* only cols have been assembled out of LUson */
+                   /* ------------------------------------------------------ */
+
+                   for (j = 0 ; j < ncols ; j++)
+                   {
+                       col = Cols [j] ;
+                       if (col >= 0)
+                       {
+#ifndef FIXQ
+                           Col_degree [col] -= nrowsleft ;
+#endif
+                           Fcol = Fcblock + Fcpos [col] ;
+#pragma ivdep
+                           for (i = 0 ; i < nrows ; i++)
+                           {
+                               /* Fcol [Wm [i]] += S [i] ; */
+                               ASSEMBLE (Fcol [Wm [i]], S [i]) ;
+                           }
+                       }
+                       S += nrows ;
+                   }
+
+               }
+               /* ] done using Wm [0..nrows-1] for offsets */
+           }
+           else
+           {
+               /* ---------------------------------------------------------- */
+               /* some rows have been assembled out of this LUson */
+               /* ---------------------------------------------------------- */
+
+               /* compute the compressed column offset vector*/
+               /* [ use Woo,Wm [0..nrowsleft-1] for offsets */
+               ngetrows = 0 ;
+               for (i = 0 ; i < nrows ; i++)
+               {
+                   row = Rows [i] ;
+                   if (row >= 0)
+                   {
+                       Row_degree [row] -= ncolsleft ;
+                       Woo [ngetrows] = i ;
+                       Wm [ngetrows++] = Frpos [row] ;
+                   }
+               }
+               ASSERT (ngetrows == nrowsleft) ;
+
+               if (ncols == ncolsleft)
+               {
+                   /* ------------------------------------------------------ */
+                   /* only rows have been assembled out of this LUson */
+                   /* ------------------------------------------------------ */
+
+                   for (j = 0 ; j < ncols ; j++)
+                   {
+                       col = Cols [j] ;
+#ifndef FIXQ
+                       Col_degree [col] -= nrowsleft ;
+#endif
+                       Fcol = Fcblock + Fcpos [col] ;
+#pragma ivdep
+                       for (i = 0 ; i < nrowsleft ; i++)
+                       {
+                           /* Fcol [Wm [i]] += S [Woo [i]] ; */
+                           ASSEMBLE (Fcol [Wm [i]], S [Woo [i]]) ;
+                       }
+                       S += nrows ;
+                   }
+
+               }
+               else
+               {
+                   /* ------------------------------------------------------ */
+                   /* both rows and columns have been assembled out of LUson */
+                   /* ------------------------------------------------------ */
+
+                   for (j = 0 ; j < ncols ; j++)
+                   {
+                       col = Cols [j] ;
+                       if (col >= 0)
+                       {
+#ifndef FIXQ
+                           Col_degree [col] -= nrowsleft ;
+#endif
+                           Fcol = Fcblock + Fcpos [col] ;
+#pragma ivdep
+                           for (i = 0 ; i < nrowsleft ; i++)
+                           {
+                               /* Fcol [Wm [i]] += S [Woo [i]] ; */
+                               ASSEMBLE (Fcol [Wm [i]], S [Woo [i]]) ;
+                           }
+                       }
+                       S += nrows ;
+                   }
+
+               }
+               /* ] done using Woo,Wm [0..nrowsleft-1] */
+           }
+
+           /* deallocate the element: remove from ordered list */
+           UMF_mem_free_tail_block (Numeric, E [e]) ;
+           E [e] = 0 ;
+
+       }
+       else if (extcdeg == 0)
+       {
+
+           /* -------------------------------------------------------------- */
+           /* this is a Uson - assemble all possible columns */
+           /* -------------------------------------------------------------- */
+
+           DEBUG6 (("New USON: "ID"\n", e)) ;
+           ASSERT (extrdeg > 0) ;
+
+           DEBUG6 (("New uson "ID" cols to do "ID"\n", e, ncols_to_assemble)) ;
+
+           if (ncols_to_assemble > 0)
+           {
+
+               Int skip = FALSE ;
+               if (ncols_to_assemble * 16 < ncols && nrows == 1)
+               {
+                   /* this is a tall and thin frontal matrix consisting of
+                    * only one column (most likely an original column). Do
+                    * not assemble it.   It cannot be the pivot column, since
+                    * the pivot column element would be an LU son, not an Lson,
+                    * of the current frontal matrix. */
+                   ASSERT (nrowsleft == 1) ;
+                   ASSERT (Rows [0] >= 0 && Rows [0] < Work->n_row) ;
+                   skip = TRUE ;
+                   Work->any_skip = TRUE ;
+               }
+
+               if (!skip)
+               {
+
+                   if (nrows == nrowsleft)
+                   {
+                       /* -------------------------------------------------- */
+                       /* no rows have been assembled out of this Uson yet */
+                       /* -------------------------------------------------- */
+
+                       /* compute the compressed column offset vector */
+                       /* [ use Wm [0..nrows-1] for offsets */
+#pragma ivdep
+                       for (i = 0 ; i < nrows ; i++)
+                       {
+                           row = Rows [i] ;
+                           ASSERT (row >= 0 && row < n_row) ;
+                           Row_degree [row] -= ncols_to_assemble ;
+                           Wm [i] = Frpos [row] ;
+                       }
+
+                       for (j = 0 ; j < ncols ; j++)
+                       {
+                           col = Cols [j] ;
+                           if ((col >= 0) && (Fcpos [col] >= 0))
+                           {
+#ifndef FIXQ
+                               Col_degree [col] -= nrowsleft ;
+#endif
+                               Fcol = Fcblock + Fcpos [col] ;
+#pragma ivdep
+                               for (i = 0 ; i < nrows ; i++)
+                               {
+                                   /* Fcol [Wm [i]] += S [i] ; */
+                                   ASSEMBLE (Fcol [Wm [i]], S [i]) ;
+                               }
+                               /* flag the column as assembled from Uson */
+                               Cols [j] = EMPTY ;
+                           }
+                           S += nrows ;
+                       }
+
+
+                       /* ] done using Wm [0..nrows-1] for offsets */
+                   }
+                   else
+                   {
+                       /* -------------------------------------------------- */
+                       /* some rows have been assembled out of this Uson */
+                       /* -------------------------------------------------- */
+
+                       /* compute the compressed column offset vector*/
+                       /* [ use Woo,Wm [0..nrows-1] for offsets */
+                       ngetrows = 0 ;
+                       for (i = 0 ; i < nrows ; i++)
+                       {
+                           row = Rows [i] ;
+                           if (row >= 0)
+                           {
+                               Row_degree [row] -= ncols_to_assemble ;
+                               ASSERT (row < n_row && Frpos [row] >= 0) ;
+                               Woo [ngetrows] = i ;
+                               Wm [ngetrows++] = Frpos [row] ;
+                           }
+                       }
+                       ASSERT (ngetrows == nrowsleft) ;
+
+                       for (j = 0 ; j < ncols ; j++)
+                       {
+                           col = Cols [j] ;
+                           if ((col >= 0) && (Fcpos [col] >= 0))
+                           {
+#ifndef FIXQ
+                               Col_degree [col] -= nrowsleft ;
+#endif
+                               Fcol = Fcblock + Fcpos [col] ;
+#pragma ivdep
+                               for (i = 0 ; i < nrowsleft ; i++)
+                               {
+                                   /* Fcol [Wm [i]] += S [Woo [i]] ; */
+                                   ASSEMBLE (Fcol [Wm [i]], S [Woo [i]]) ;
+                               }
+                               /* flag the column as assembled from Uson */
+                               Cols [j] = EMPTY ;
+                           }
+                           S += nrows ;
+                       }
+
+                       /* ] done using Woo,Wm */
+                   }
+                   ep->ncolsleft = extrdeg ;
+               }
+           }
+
+       }
+       else
+       {
+
+           /* -------------------------------------------------------------- */
+           /* this is an Lson - assemble all possible rows */
+           /* -------------------------------------------------------------- */
+
+           DEBUG6 (("New LSON: "ID"\n", e)) ;
+           ASSERT (extrdeg == 0 && extcdeg > 0) ;
+
+           DEBUG6 (("New lson "ID" rows to do "ID"\n", e, nrows_to_assemble)) ;
+
+           if (nrows_to_assemble > 0)
+           {
+
+               Int skip = FALSE ;
+               if (nrows_to_assemble * 16 < nrows && ncols == 1)
+               {
+                   /* this is a tall and thin frontal matrix consisting of
+                    * only one column (most likely an original column). Do
+                    * not assemble it.   It cannot be the pivot column, since
+                    * the pivot column element would be an LU son, not an Lson,
+                    * of the current frontal matrix. */
+                   ASSERT (ncolsleft == 1) ;
+                   ASSERT (Cols [0] >= 0 && Cols [0] < Work->n_col) ;
+                   Work->any_skip = TRUE ;
+                   skip = TRUE ;
+               }
+
+               if (!skip)
+               {
+
+                   /* compute the compressed column offset vector */
+                   /* [ use Woo,Wm [0..nrows-1] for offsets */
+                   ngetrows = 0 ;
+                   for (i = 0 ; i < nrows ; i++)
+                   {
+                       row = Rows [i] ;
+                       if ((row >= 0) && (Frpos [row] >= 0))
+                       {
+                           ASSERT (row < n_row) ;
+                           Row_degree [row] -= ncolsleft ;
+                           Woo [ngetrows] = i ;
+                           Wm [ngetrows++] = Frpos [row] ;
+                           /* flag the row as assembled from the Lson */
+                           Rows [i] = EMPTY ;
+                       }
+                   }
+                   ASSERT (nrowsleft - ngetrows == extcdeg) ;
+                   ASSERT (ngetrows == nrows_to_assemble) ;
+
+                   if (ncols == ncolsleft)
+                   {
+                       /* -------------------------------------------------- */
+                       /* no columns assembled out this Lson yet */
+                       /* -------------------------------------------------- */
+
+                       for (j = 0 ; j < ncols ; j++)
+                       {
+                           col = Cols [j] ;
+                           ASSERT (col >= 0 && col < n_col) ;
+#ifndef FIXQ
+                           Col_degree [col] -= nrows_to_assemble ;
+#endif
+                           Fcol = Fcblock + Fcpos [col] ;
+#pragma ivdep
+                           for (i = 0 ; i < nrows_to_assemble ; i++)
+                           {
+                               /* Fcol [Wm [i]] += S [Woo [i]] ; */
+                               ASSEMBLE (Fcol [Wm [i]], S [Woo [i]]) ;
+                           }
+                           S += nrows ;
+                       }
+
+
+                   }
+                   else
+                   {
+                       /* -------------------------------------------------- */
+                       /* some columns have been assembled out of this Lson */
+                       /* -------------------------------------------------- */
+
+                       for (j = 0 ; j < ncols ; j++)
+                       {
+                           col = Cols [j] ;
+                           ASSERT (col < n_col) ;
+                           if (col >= 0)
+                           {
+#ifndef FIXQ
+                               Col_degree [col] -= nrows_to_assemble ;
+#endif
+                               Fcol = Fcblock + Fcpos [col] ;
+#pragma ivdep
+                               for (i = 0 ; i < nrows_to_assemble ; i++)
+                               {
+                                   /* Fcol [Wm [i]] += S [Woo [i]] ; */
+                                   ASSEMBLE (Fcol [Wm [i]], S [Woo [i]]) ;
+                               }
+                           }
+                           S += nrows ;
+                       }
+
+                   }
+
+                   /* ] done using Woo,Wm */
+
+                   ep->nrowsleft = extcdeg ;
+               }
+           }
+       }
+    }
+
+    /* Note that garbage collection, and build tuples */
+    /* both destroy the son list. */
+
+    /* ] son_list now empty */
+
+    /* ---------------------------------------------------------------------- */
+    /* If frontal matrix extended, assemble old L/Usons from new rows/cols */
+    /* ---------------------------------------------------------------------- */
+
+    /* ---------------------------------------------------------------------- */
+    /* SCAN2-row:  assemble rows of old Lsons from the new rows */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    DEBUG7 (("Current frontal matrix: (prior to scan2-row)\n")) ;
+    UMF_dump_current_front (Numeric, Work, TRUE) ;
+#endif
+
+    /* rescan the pivot row */
+    if (Work->any_skip)
+    {
+       row_assemble (Work->pivrow, Numeric, Work) ;
+    }
+
+    if (Work->do_scan2row)
+    {
+       for (i2 = Work->fscan_row ; i2 < fnrows ; i2++)
+       {
+           /* Get a row */
+           row = Work->NewRows [i2] ;
+           if (row < 0) row = FLIP (row) ;
+           ASSERT (row >= 0 && row < n_row) ;
+           if (!(row == Work->pivrow && Work->any_skip))
+           {
+               /* assemble it */
+               row_assemble (row, Numeric, Work) ;
+           }
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* SCAN2-col:  assemble columns of old Usons from the new columns */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    DEBUG7 (("Current frontal matrix: (prior to scan2-col)\n")) ;
+    UMF_dump_current_front (Numeric, Work, TRUE) ;
+#endif
+
+    /* rescan the pivot col */
+    if (Work->any_skip)
+    {
+       col_assemble (Work->pivcol, Numeric, Work) ;
+    }
+
+    if (Work->do_scan2col)
+    {
+
+       for (j2 = Work->fscan_col ; j2 < fncols ; j2++)
+       {
+           /* Get a column */
+           col = Work->NewCols [j2] ;
+           if (col < 0) col = FLIP (col) ;
+           ASSERT (col >= 0 && col < n_col) ;
+           if (!(col == Work->pivcol && Work->any_skip))
+           {
+               /* assemble it */
+               col_assemble (col, Numeric, Work) ;
+           }
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* done.  the remainder of this routine is used only when in debug mode */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+
+    /* ---------------------------------------------------------------------- */
+    /* when debugging: make sure the assembly did everything that it could */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG3 (("::Assemble done\n")) ;
+
+    for (i2 = 0 ; i2 < fnrows ; i2++)
+    {
+       /* Get a row */
+       row = Work->Frows [i2] ;
+       ASSERT (row >= 0 && row < n_row) ;
+
+       DEBUG6 (("DEBUG SCAN 1: "ID"\n", row)) ;
+       UMF_dump_rowcol (0, Numeric, Work, row, TRUE) ;
+
+       ASSERT (NON_PIVOTAL_ROW (row)) ;
+       tpi = Row_tuples [row] ;
+       if (!tpi) continue ;
+       tp = (Tuple *) (Memory + tpi) ;
+       tpend = tp + Row_tlen [row] ;
+       for ( ; tp < tpend ; tp++)
+       {
+           e = tp->e ;
+           ASSERT (e > 0 && e <= Work->nel) ;
+           if (!E [e]) continue ;      /* element already deallocated */
+           f = tp->f ;
+           p = Memory + E [e] ;
+           ep = (Element *) p ;
+           p += UNITS (Element, 1) ;
+           Cols = (Int *) p ;
+           Rows = ((Int *) p) + ep->ncols ;
+           if (Rows [f] == EMPTY) continue ;   /* row already assembled */
+           ASSERT (row == Rows [f]) ;
+           extrdeg = (ep->rdeg < rdeg0) ? ep->ncolsleft : (ep->rdeg - rdeg0) ;
+           extcdeg = (ep->cdeg < cdeg0) ? ep->nrowsleft : (ep->cdeg - cdeg0) ;
+           DEBUG6 ((
+               "e "ID" After assembly ext row deg: "ID" ext col degree "ID"\n",
+               e, extrdeg, extcdeg)) ;
+
+           if (Work->any_skip)
+           {
+               /* no Lsons in any row, except for very tall and thin ones */
+               ASSERT (extrdeg >= 0) ;
+               if (extrdeg == 0)
+               {
+                   /* this is an unassemble Lson */
+                   ASSERT (ep->ncols == 1) ;
+                   ASSERT (ep->ncolsleft == 1) ;
+                   col = Cols [0] ;
+                   ASSERT (col != Work->pivcol) ;
+               }
+           }
+           else
+           {
+               /* no Lsons in any row */
+               ASSERT (extrdeg > 0) ;
+               /* Uson external row degree is = number of cols left */
+               ASSERT (IMPLIES (extcdeg == 0, extrdeg == ep->ncolsleft)) ;
+           }
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+
+    for (j2 = 0 ; j2 < fncols ; j2++)
+    {
+       /* Get a column */
+       col = Work->Fcols [j2] ;
+       ASSERT (col >= 0 && col < n_col) ;
+
+       DEBUG6 (("DEBUG SCAN 2: "ID"\n", col)) ;
+#ifndef FIXQ
+       UMF_dump_rowcol (1, Numeric, Work, col, TRUE) ;
+#else
+       UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ;
+#endif
+
+       ASSERT (NON_PIVOTAL_COL (col)) ;
+       tpi = Col_tuples [col] ;
+       if (!tpi) continue ;
+       tp = (Tuple *) (Memory + tpi) ;
+       tpend = tp + Col_tlen [col] ;
+       for ( ; tp < tpend ; tp++)
+       {
+           e = tp->e ;
+           ASSERT (e > 0 && e <= Work->nel) ;
+           if (!E [e]) continue ;      /* element already deallocated */
+           f = tp->f ;
+           p = Memory + E [e] ;
+           ep = (Element *) p ;
+           p += UNITS (Element, 1) ;
+           Cols = (Int *) p ;
+           Rows = ((Int *) p) + ep->ncols ;
+           if (Cols [f] == EMPTY) continue ;   /* column already assembled */
+           ASSERT (col == Cols [f]) ;
+           extrdeg = (ep->rdeg < rdeg0) ? ep->ncolsleft : (ep->rdeg - rdeg0) ;
+           extcdeg = (ep->cdeg < cdeg0) ? ep->nrowsleft : (ep->cdeg - cdeg0) ;
+           DEBUG6 (("e "ID" After assembly ext col deg: "ID"\n", e, extcdeg)) ;
+
+           if (Work->any_skip)
+           {
+               /* no Usons in any column, except for very tall and thin ones */
+               ASSERT (extcdeg >= 0) ;
+               if (extcdeg == 0)
+               {
+                   /* this is an unassemble Uson */
+                   ASSERT (ep->nrows == 1) ;
+                   ASSERT (ep->nrowsleft == 1) ;
+                   row = Rows [0] ;
+                   ASSERT (row != Work->pivrow) ;
+               }
+           }
+           else
+           {
+               /* no Usons in any column */
+               ASSERT (extcdeg > 0) ;
+               /* Lson external column degree is = number of rows left */
+               ASSERT (IMPLIES (extrdeg == 0, extcdeg == ep->nrowsleft)) ;
+           }
+       }
+    }
+#endif /* NDEBUG */
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_assemble.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_assemble.h
new file mode 100644 (file)
index 0000000..4cbfc57
--- /dev/null
@@ -0,0 +1,18 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_assemble
+(
+    NumericType *Numeric,
+    WorkType *Work
+) ;
+
+GLOBAL void UMF_assemble_fixq
+(
+    NumericType *Numeric,
+    WorkType *Work
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_blas3_update.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_blas3_update.c
new file mode 100644 (file)
index 0000000..acceb5f
--- /dev/null
@@ -0,0 +1,165 @@
+/* ========================================================================== */
+/* === UMF_blas3_update ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+#include "umf_internal.h"
+
+GLOBAL void UMF_blas3_update
+(
+    WorkType *Work
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Entry *L, *U, *C, *LU ;
+    Int k, m, n, d, nb, dc ;
+
+    DEBUG5 (("In UMF_blas3_update "ID" "ID" "ID"\n",
+       Work->fnpiv, Work->fnrows, Work->fncols)) ;
+
+    k = Work->fnpiv ;
+    if (k == 0)
+    {
+       /* no work to do */
+       return ;
+    }
+
+    m = Work->fnrows ;
+    n = Work->fncols ;
+
+    d = Work->fnr_curr ;
+    dc = Work->fnc_curr ;
+    nb = Work->nb ;
+    ASSERT (d >= 0 && (d % 2) == 1) ;
+    C = Work->Fcblock ;            /* ldc is fnr_curr */
+    L =        Work->Flblock ;     /* ldl is fnr_curr */
+    U = Work->Fublock ;            /* ldu is fnc_curr, stored by rows */
+    LU = Work->Flublock ;   /* nb-by-nb */
+
+#ifndef NDEBUG
+    DEBUG5 (("DO RANK-NB UPDATE of frontal:\n")) ;
+    DEBUG5 (("DGEMM : "ID" "ID" "ID"\n", k, m, n)) ;
+    DEBUG7 (("C  block: ")) ; UMF_dump_dense (C,  d, m, n) ;
+    DEBUG7 (("A  block: ")) ; UMF_dump_dense (L,  d, m, k) ;
+    DEBUG7 (("B' block: ")) ; UMF_dump_dense (U, dc, n, k) ;
+    DEBUG7 (("LU block: ")) ; UMF_dump_dense (LU, nb, k, k) ;
+#endif
+
+    if (k == 1)
+    {
+
+#ifdef USE_NO_BLAS
+
+       /* no BLAS available - use plain C code instead */
+       Int i, j ;
+
+       /* rank-1 outer product to update the C block */
+       for (j = 0 ; j < n ; j++)
+       {
+           Entry u_j = U [j] ;
+           if (IS_NONZERO (u_j))
+           {
+               Entry *c_ij, *l_is ;
+               c_ij = & C [j*d] ;
+               l_is = & L [0] ;
+#pragma ivdep
+               for (i = 0 ; i < m ; i++)
+               {
+                   /* C [i+j*d]-= L [i] * U [j] */
+                   MULT_SUB (*c_ij, *l_is, u_j) ;
+                   c_ij++ ;
+                   l_is++ ;
+               }
+           }
+       }
+
+#else
+       BLAS_GER (m, n, L, U, C, d) ;
+
+#endif /* USE_NO_BLAS */
+
+    }
+    else
+    {
+
+#ifdef USE_NO_BLAS
+
+       /* no BLAS available - use plain C code instead */
+       Int i, j, s ;
+
+       /* triangular solve to update the U block */
+       for (s = 0 ; s < k ; s++)
+       {
+           for (i = s+1 ; i < k ; i++)
+           {
+               Entry l_is = LU [i+s*nb] ;
+               if (IS_NONZERO (l_is))
+               {
+                   Entry *u_ij, *u_sj ;
+                   u_ij = & U [i*dc] ;
+                   u_sj = & U [s*dc] ;
+#pragma ivdep
+                   for (j = 0 ; j < n ; j++)
+                   {
+                       /* U [i*dc+j] -= LU [i+s*nb] * U [s*dc+j] ; */
+                       MULT_SUB (*u_ij, l_is, *u_sj) ;
+                       u_ij++ ;
+                       u_sj++ ;
+                   }
+               }
+           }
+       }
+
+       /* rank-k outer product to update the C block */
+       /* C = C - L*U' (U is stored by rows, not columns) */
+       for (s = 0 ; s < k ; s++)
+       {
+           for (j = 0 ; j < n ; j++)
+           {
+               Entry u_sj = U [j+s*dc] ;
+               if (IS_NONZERO (u_sj))
+               {
+                   Entry *c_ij, *l_is ;
+                   c_ij = & C [j*d] ;
+                   l_is = & L [s*d] ;
+#pragma ivdep
+                   for (i = 0 ; i < m ; i++)
+                   {
+                       /* C [i+j*d]-= L [i+s*d] * U [s*dc+j] */
+                       MULT_SUB (*c_ij, *l_is, u_sj) ;
+                       c_ij++ ;
+                       l_is++ ;
+                   }
+               }
+           }
+       }
+
+#else
+
+       BLAS_TRSM_RIGHT (n, k, LU, nb, U, dc) ;
+       BLAS_GEMM (m, n, k, L, U, dc, C, d) ;
+
+#endif /* USE_NO_BLAS */
+
+    }
+
+#ifndef NDEBUG
+    DEBUG5 (("RANK-NB UPDATE of frontal done:\n")) ;
+    DEBUG5 (("DGEMM : "ID" "ID" "ID"\n", k, m, n)) ;
+    DEBUG7 (("C  block: ")) ; UMF_dump_dense (C,  d, m, n) ;
+    DEBUG7 (("A  block: ")) ; UMF_dump_dense (L,  d, m, k) ;
+    DEBUG7 (("B' block: ")) ; UMF_dump_dense (U, dc, n, k) ;
+    DEBUG7 (("LU block: ")) ; UMF_dump_dense (LU, nb, k, k) ;
+#endif
+
+    DEBUG2 (("blas3 "ID" "ID" "ID"\n", k, Work->fnrows, Work->fncols)) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_blas3_update.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_blas3_update.h
new file mode 100644 (file)
index 0000000..2285d97
--- /dev/null
@@ -0,0 +1,11 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_blas3_update
+(
+    WorkType *Work
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_build_tuples.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_build_tuples.c
new file mode 100644 (file)
index 0000000..cabb7e0
--- /dev/null
@@ -0,0 +1,160 @@
+/* ========================================================================== */
+/* === UMF_build_tuples ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Construct the tuple lists from a set of packed elements (no holes in
+    elements, no internal or external fragmentation, and a packed (0..Work->nel)
+    element name space).  Assume no tuple lists are currently allocated, but
+    that the tuple lengths have been initialized by UMF_tuple_lengths.
+
+    Returns TRUE if successful, FALSE if not enough memory.
+*/
+
+#include "umf_internal.h"
+#include "umf_mem_alloc_tail_block.h"
+
+GLOBAL Int UMF_build_tuples
+(
+    NumericType *Numeric,
+    WorkType *Work
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int e, nrows, ncols, nel, *Rows, *Cols, row, col, n_row, n_col, *E,
+       *Row_tuples, *Row_degree, *Row_tlen,
+       *Col_tuples, *Col_degree, *Col_tlen, n1 ;
+    Element *ep ;
+    Unit *p ;
+    Tuple tuple, *tp ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    E = Work->E ;
+    Col_degree = Numeric->Cperm ;      /* for NON_PIVOTAL_COL macro */
+    Row_degree = Numeric->Rperm ;      /* for NON_PIVOTAL_ROW macro */
+    Row_tuples = Numeric->Uip ;
+    Row_tlen   = Numeric->Uilen ;
+    Col_tuples = Numeric->Lip ;
+    Col_tlen   = Numeric->Lilen ;
+    n_row = Work->n_row ;
+    n_col = Work->n_col ;
+    nel = Work->nel ;
+    n1 = Work->n1 ;
+
+    DEBUG3 (("BUILD_TUPLES: n_row "ID" n_col "ID" nel "ID"\n",
+       n_row, n_col, nel)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate space for the tuple lists */
+    /* ---------------------------------------------------------------------- */
+
+    /* Garbage collection and memory reallocation have already attempted to */
+    /* ensure that there is enough memory for all the tuple lists.  If */
+    /* memory allocation fails here, then there is nothing more to be done. */
+
+    for (row = n1 ; row < n_row ; row++)
+    {
+       if (NON_PIVOTAL_ROW (row))
+       {
+           Row_tuples [row] = UMF_mem_alloc_tail_block (Numeric,
+               UNITS (Tuple, TUPLES (Row_tlen [row]))) ;
+           if (!Row_tuples [row])
+           {
+               /* :: out of memory for row tuples :: */
+               DEBUGm4 (("out of memory: build row tuples\n")) ;
+               return (FALSE) ;        /* out of memory for row tuples */
+           }
+           Row_tlen [row] = 0 ;
+       }
+    }
+
+    /* push on stack in reverse order, so column tuples are in the order */
+    /* that they will be deleted. */
+    for (col = n_col-1 ; col >= n1 ; col--)
+    {
+       if (NON_PIVOTAL_COL (col))
+       {
+           Col_tuples [col] = UMF_mem_alloc_tail_block (Numeric,
+               UNITS (Tuple, TUPLES (Col_tlen [col]))) ;
+           if (!Col_tuples [col])
+           {
+               /* :: out of memory for col tuples :: */
+               DEBUGm4 (("out of memory: build col tuples\n")) ;
+               return (FALSE) ;        /* out of memory for col tuples */
+           }
+           Col_tlen [col] = 0 ;
+       }
+    }
+
+#ifndef NDEBUG
+    UMF_dump_memory (Numeric) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* create the tuple lists (exclude element 0) */
+    /* ---------------------------------------------------------------------- */
+
+    /* for all elements, in order of creation */
+    for (e = 1 ; e <= nel ; e++)
+    {
+       DEBUG9 (("Adding tuples for element: "ID" at "ID"\n", e, E [e])) ;
+       ASSERT (E [e]) ;        /* no external fragmentation */
+       p = Numeric->Memory + E [e] ;
+       GET_ELEMENT_PATTERN (ep, p, Cols, Rows, ncols) ;
+       nrows = ep->nrows ;
+       ASSERT (e != 0) ;
+       ASSERT (e == 0 || nrows == ep->nrowsleft) ;
+       ASSERT (e == 0 || ncols == ep->ncolsleft) ;
+       tuple.e = e ;
+       for (tuple.f = 0 ; tuple.f < ncols ; tuple.f++)
+       {
+           col = Cols [tuple.f] ;
+           ASSERT (col >= n1 && col < n_col) ;
+           ASSERT (NON_PIVOTAL_COL (col)) ;
+           ASSERT (Col_tuples [col]) ;
+           tp = ((Tuple *) (Numeric->Memory + Col_tuples [col]))
+               + Col_tlen [col]++ ;
+           *tp = tuple ;
+#ifndef NDEBUG
+           UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ;
+#endif
+       }
+       for (tuple.f = 0 ; tuple.f < nrows ; tuple.f++)
+       {
+           row = Rows [tuple.f] ;
+           ASSERT (row >= n1 && row < n_row) ;
+           ASSERT (NON_PIVOTAL_COL (col)) ;
+           ASSERT (Row_tuples [row]) ;
+           tp = ((Tuple *) (Numeric->Memory + Row_tuples [row]))
+               + Row_tlen [row]++ ;
+           *tp = tuple ;
+#ifndef NDEBUG
+           UMF_dump_rowcol (0, Numeric, Work, row, FALSE) ;
+#endif
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* the tuple lists are now valid, and can be scanned */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    UMF_dump_memory (Numeric) ;
+    UMF_dump_matrix (Numeric, Work, FALSE) ;
+#endif
+    DEBUG3 (("BUILD_TUPLES: done\n")) ;
+    return (TRUE) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_build_tuples.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_build_tuples.h
new file mode 100644 (file)
index 0000000..a4b5ed1
--- /dev/null
@@ -0,0 +1,12 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_build_tuples
+(
+    NumericType *Numeric,
+    WorkType *Work
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_colamd.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_colamd.c
new file mode 100644 (file)
index 0000000..8a574dd
--- /dev/null
@@ -0,0 +1,3140 @@
+/* ========================================================================== */
+/* === UMF_colamd =========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+UMF_colamd:  an approximate minimum degree column ordering algorithm,
+    used as a preordering for UMFPACK.
+
+NOTE: if this routine is used outside of UMFPACK, for a sparse Cholesky
+factorization of (AQ)'*(AQ) or a QR factorization of A, then one line should
+be removed (the "&& pivot_row_thickness > 0" expression).  See the comment
+regarding the Cholesky factorization, below.
+
+Purpose:
+
+    Colamd computes a permutation Q such that the Cholesky factorization of
+    (AQ)'(AQ) has less fill-in and requires fewer floating point operations
+    than A'A.  This also provides a good ordering for sparse partial
+    pivoting methods, P(AQ) = LU, where Q is computed prior to numerical
+    factorization, and P is computed during numerical factorization via
+    conventional partial pivoting with row interchanges.  Colamd is the
+    column ordering method used in SuperLU, part of the ScaLAPACK library.
+    It is also available as built-in function in MATLAB Version 6,
+    available from MathWorks, Inc. (http://www.mathworks.com).  This
+    routine can be used in place of colmmd in MATLAB.  By default, the \
+    and / operators in MATLAB perform a column ordering (using colmmd
+    or colamd) prior to LU factorization using sparse partial pivoting,
+    in the built-in MATLAB lu(A) routine.
+
+    This code is derived from Colamd Version 2.0.
+
+Authors:
+
+    The authors of the COLAMD code itself are Stefan I. Larimore and Timothy A.
+    Davis, University of Florida.  The algorithm was developed in collaboration
+    with John Gilbert, Xerox PARC, and Esmond Ng, Oak Ridge National Laboratory.
+    The AMD metric on which this is based is by Patrick Amestoy, T. Davis,
+    and Iain Duff.
+
+Date:
+
+    UMFPACK Version: see above.
+    COLAMD Version 2.0 was released on January 31, 2000.
+
+Acknowledgements:
+
+    This work was supported by the National Science Foundation, under
+    grants DMS-9504974, 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/deal.II/contrib/umfpack/UMFPACK/Source/umf_colamd.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_colamd.h
new file mode 100644 (file)
index 0000000..b33ebe1
--- /dev/null
@@ -0,0 +1,256 @@
+/* ========================================================================== */
+/* === umf_colamd.h ========================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+
+Authors:
+
+    The authors of the COLAMD code itself are Stefan I. Larimore and Timothy A.
+    Davis, University of Florida.  The algorithm was developed in collaboration
+    with John Gilbert, Xerox PARC, and Esmond Ng, Oak Ridge National Laboratory.
+
+Date:
+
+    UMFPACK Version: see above.
+    COLAMD Version 2.0 was released on January 31, 2000.
+
+Acknowledgements:
+
+    This work was supported by the National Science Foundation, under
+    grants DMS-9504974, 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/deal.II/contrib/umfpack/UMFPACK/Source/umf_config.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_config.h
new file mode 100644 (file)
index 0000000..ea4b641
--- /dev/null
@@ -0,0 +1,920 @@
+/* ========================================================================== */
+/* === umf_config.h ========================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    This file controls the compile-time configuration of UMFPACK.  Modify the
+    Makefile, the architecture-dependent Make.* file, and this file if
+    necessary, to control these options.  The following flags may be given
+    as options to your C compiler (as in "cc -DNBLAS", for example).  These
+    flags are normally placed in your CONFIG string, defined in your Make.*.
+
+    All of these options, except for the timer, are for accessing the BLAS.
+
+       -DNBLAS
+
+           BLAS mode.  If -DNBLAS is set, then no BLAS will be used.  Vanilla
+           C code will be used instead.  This is portable, and easier to
+           install, but you won't get the best performance.
+
+           If -DNBLAS is not set, then externally-available BLAS routines
+           (dgemm, dger, and dgemv or the equivalent C-BLAS routines) will be
+           used.  This will give you the best performance, but perhaps at the
+           expense of portability.
+
+           The default is to use the BLAS, for both the C-callable libumfpack.a
+           library and the MATLAB mexFunction.  If you have trouble installing
+           UMFPACK, set -DNBLAS (but then UMFPACK will be slow).
+
+       -DCBLAS
+
+           If -DCBLAS is set, then the C-BLAS interface to the BLAS is
+           used.  If your vendor-supplied BLAS library does not have a C-BLAS
+           interface, you can obtain the ATLAS BLAS, available at
+           http://www.netlib.org/atlas.
+
+           This flag is ignored if -DNBLAS is set.
+
+       -DLP64
+
+           This should be defined if you are compiling in the LP64 model
+           (32 bit int's, 64 bit long's, and 64 bit pointers).  In Solaris,
+           this is obtained with the flags -xtarget=ultra -xarch=v9 for
+           the cc compiler (for example).
+
+       -DLONGBLAS
+
+           If not defined, then the BLAS are not called in the long integer
+           version of UMFPACK (the umfpack_*l_* routines).  The most common
+           definitions of the BLAS, unfortunately, use int arguments, and
+           are thus not suitable for use in the LP64 model.  Only the Sun
+           Performance Library, as far as I can tell, has a version of the
+           BLAS that allows long integer (64-bit) input arguments.  This
+           flag is set automatically in Sun Solaris if you are using the
+           Sun Performance BLAS.  You can set it yourself, too, if your BLAS
+           routines can take long integer input arguments.
+
+       -DNSUNPERF
+
+           Applies only to Sun Solaris.  If -DNSUNPERF is set, then the Sun
+           Performance Library BLAS will not be used.
+
+           The Sun Performance Library BLAS is used by default when compiling
+           the C-callable libumfpack.a library on Sun Solaris.
+
+           This flag is ignored if -DNBLAS is set.
+
+       -DNSCSL
+
+           Applies only to SGI IRIX.  If -DSCSL is set, then the SGI SCSL
+           Scientific Library BLAS will not be used.
+
+           The SGI SCSL Scientific Library BLAS is used by default when
+           compiling the C-callable libumfpack.a library on SGI IRIX.
+
+           This flag is ignored if -DNBLAS is set.
+
+       -DNPOSIX
+
+           If -DNPOSIX is set, then your Unix operating system is not POSIX-
+           compliant, and the POSIX routines sysconf ( ) and times ( )
+           routines are not used.  These routines provide CPU time and
+           wallclock time information.  If -DNPOSIX is set, then the ANSI
+           C clock ( ) routine is used.  If -DNPOSIX is not set, then
+           sysconf ( ) and times ( ) are used in umfpack_tic and umfpack_toc.
+           See umfpack_tictoc.c for more information.
+           The default is to use the POSIX routines, except for Windows,
+           which is not POSIX-compliant.
+
+       -DGETRUSAGE
+
+           If -DGETRUSAGE is set, then your system's getrusage ( ) routine
+           will be used for getting the process CPU time.  Otherwise the ANSI
+           C clock ( ) routine will be used.  The default is to use getrusage
+           ( ) on Unix systems, and to use clock on all other architectures.
+
+       -DNO_TIMER
+
+           If -DNO_TIMER is set, then no timing routines are used at all.
+
+       -DNUTIL
+
+           If -DNUTIL is set, then the internal MATLAB utMalloc, utFree, and
+           utRealloc routines are not used in the UMFPACK mexFunction.  The
+           regular mxMalloc, mxFree, and mxRealloc routines are used instead.
+           These routines are not documented, but are available for use.  For
+           Windows, -DNUTIL is defined below, because access to the ut*
+           routines is not available by default.
+
+       -DNRECIPROCAL
+
+           This option controls a tradeoff between speed and accuracy.  Using
+           -DNRECIPROCAL can lead to more accurate results, but with perhaps
+           some cost in performance, particularly if floating-point division
+           is much more costly than floating-point multiplication.
+
+           This option determines the method used to scale the pivot column.
+           If set, or if the absolute value of the pivot is < 1e-12 (or is a
+           NaN), then the pivot column is divided by the pivot value.
+           Otherwise, the reciprocal of the pivot value is computed, and the
+           pivot column is multiplied by (1/pivot).  Multiplying by the
+           reciprocal can be slightly less accurate than dividing by the
+           pivot, but it is often faster.  See umf_scale.c.
+
+           This has a small effect on the performance of UMFPACK, at least on
+           a Pentium 4M.  It may have a larger effect on other architectures
+           where floating-point division is much more costly than floating-
+           point multiplication.  The RS 6000 is one such example.
+
+           By default, the method chosen is to multiply by the reciprocal
+           (sacrificing accuracy for speed), except when compiling UMFPACK
+           as a built-in routine in MATLAB, or when gcc is being used.
+
+           When MATHWORKS is defined, -DNRECIPROCAL is forced on, and the pivot
+           column is divided by the pivot value.  The only way of using the
+           other method in this case is to edit this file.
+
+           If -DNRECIPROCAL is enabled, then the row scaling factors are always
+           applied by dividing each row by the scale factor, rather than
+           multiplying by the reciprocal.  If -DNRECIPROCAL is not enabled
+           (the default case), then the scale factors are normally applied by
+           multiplying by the reciprocal.  If, however, the smallest scale
+           factor is tiny, then the scale factors are applied via division.
+
+       -DNO_DIVIDE_BY_ZERO
+
+           If the pivot is zero, and this flag is set, then no divide-by-zero
+           occurs.
+
+    You should normally not set these flags yourself:
+
+       -DBLAS_BY_VALUE         if scalars are passed by value, not reference
+       -DBLAS_NO_UNDERSCORE    if no underscore should be appended
+       -DBLAS_CHAR_ARG         if BLAS options are single char's, not strings
+
+           The BLAS options are normally set automatically.  If your
+           architecture cannot be determined (see UMFPACK_ARCHITECTURE, below)
+           then you may need to set these flags yourself.
+
+    The following options are controlled by amd_internal.h:
+
+       -DMATLAB_MEX_FILE
+
+           This flag is turned on when compiling the umfpack mexFunction for
+           use in MATLAB.  When compiling the MATLAB mexFunction, the MATLAB
+           BLAS are used (unless -DNBLAS is set).  The -DCBLAS, -DNSCSL, and
+           -DNSUNPERF flags are all ignored.   The -DNRECIPROCAL flag is
+           forced on.  Otherwise, [L,U,P,Q,R] = umfpack (A) would return
+           either L*U = P*(R\A)*Q or L*U = P*R*A*Q.  Rather than returning a
+           flag stating how the scale factors R are to be applied, the umfpack
+           mexFunction always takes the more accurate route and returns
+           L*U = P*(R\A)*Q.
+
+       -DMATHWORKS
+
+           This flag is turned on when compiling umfpack as a built-in routine
+           in MATLAB.  The MATLAB BLAS are used for all architectures (-DNBLAS,
+           -DCBLAS, -DNSCSL, and -DNSUNPERF flags are all ignored).  Internal
+           routines utMalloc, utFree, utRealloc, utPrintf, utDivideComplex,
+           and utFdlibm_hypot are used, and the "util.h" file is included.
+           This avoids the problem discussed in the User Guide regarding memory
+           allocation in MATLAB.  utMalloc returns NULL on failure, instead of
+           terminating the mexFunction (which is what mxMalloc does).  However,
+           the ut* routines are not documented by The MathWorks, Inc., so I
+           cannot guarantee that you will always be able to use them.
+           The -DNRECIPROCAL flag is turned on.
+
+       -DNDEBUG
+
+           Debugging mode (if NDEBUG is not defined).  The default, of course,
+           is no debugging.  Turning on debugging takes some work (see below).
+           If you do not edit this file, then debugging is turned off anyway,
+           regardless of whether or not -DNDEBUG is specified in your compiler
+           options.
+*/
+
+/* ========================================================================== */
+/* === AMD configuration ==================================================== */
+/* ========================================================================== */
+
+/* NDEBUG, PRINTF defined in amd_internal.h */
+
+/* ========================================================================== */
+/* === reciprocal option ==================================================== */
+/* ========================================================================== */
+
+/* Force the definition NRECIPROCAL when MATHWORKS or MATLAB_MEX_FILE
+ * are defined.  Do not multiply by the reciprocal in those cases. */
+
+#ifndef NRECIPROCAL
+#if defined (MATHWORKS) || defined (MATLAB_MEX_FILE)
+#define NRECIPROCAL
+#endif
+#endif
+
+/* ========================================================================== */
+/* === Microsoft Windows configuration ====================================== */
+/* ========================================================================== */
+
+#ifdef UMF_WINDOWS
+/* Windows can't access the ut* routines, and it isn't Unix. */
+#define NUTIL
+#define NPOSIX
+#endif
+
+/* ========================================================================== */
+/* === 0-based or 1-based printing ========================================== */
+/* ========================================================================== */
+
+#if defined (MATLAB_MEX_FILE) && defined (NDEBUG)
+/* In MATLAB, matrices are 1-based to the user, but 0-based internally. */
+/* One is added to all row and column indices when printing matrices */
+/* for the MATLAB user.  The +1 shift is turned off when debugging. */
+#define INDEX(i) ((i)+1)
+#else
+/* In ANSI C, matrices are 0-based and indices are reported as such. */
+/* This mode is also used for debug mode, and if MATHWORKS is defined rather */
+/* than MATLAB_MEX_FILE. */
+#define INDEX(i) (i)
+#endif
+
+/* ========================================================================== */
+/* === Timer ================================================================ */
+/* ========================================================================== */
+
+/*
+    If you have the getrusage routine (all Unix systems I've test do), then use
+    that.  Otherwise, use the ANSI C clock function.   Note that on many
+    systems, the ANSI clock function wraps around after only 2147 seconds, or
+    about 36 minutes.  BE CAREFUL:  if you compare the run time of UMFPACK with
+    other sparse matrix packages, be sure to use the same timer.  See
+    umfpack_tictoc.c for the timer used internally by UMFPACK.  See also
+    umfpack_timer.c for the timer used in an earlier version of UMFPACK (V4.0).
+    That timer is still available as a user-callable routine, but it is no
+    longer used internally by UMFPACK.
+*/
+
+/* Sun Solaris, SGI Irix, Linux, Compaq Alpha, and IBM RS 6000 all have */
+/* getrusage.  It's in BSD unix, so perhaps all unix systems have it. */
+#if defined (UMF_SOL2) || defined (UMF_SGI) || defined (UMF_LINUX) \
+|| defined (UMF_ALPHA) || defined (UMF_AIX)
+#define GETRUSAGE
+#endif
+
+
+/* ========================================================================== */
+/* === BLAS ================================================================= */
+/* ========================================================================== */
+
+/*
+    The adventure begins.  Figure out how to call the BLAS ...
+
+    This works, but it is incredibly ugly.  The C-BLAS was supposed to solve
+    this problem, and make it easier to interface a C program to the BLAS.
+    Unfortunately, the C-BLAS does not have a "long" integer (64 bit) version.
+    Various vendors have done their own 64-bit BLAS.  Sun has dgemm_64 routines
+    with "long" integers, SGI has a 64-bit dgemm in their scsl_blas_i8 library
+    with "long long" integers, and so on.
+
+    Different vendors also have different ways of defining a complex number,
+    some using struct's.  That's a bad idea.  See umf_version.h for the better
+    way to do it (the method that was also chosen for the complex C-BLAS,
+    which is compatible and guaranteed to be portable with ANSI C).
+
+    To make matters worse, SGI's SCSL BLAS has a C-BLAS interface which
+    differs from the ATLAS C-BLAS interface (see immediately below);
+    although a more recent version of SGI's C-BLAS interface is correct
+    if SCSL_VOID_ARGS is defined.
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* Determine which BLAS to use. */
+/* -------------------------------------------------------------------------- */
+
+#if defined (MATHWORKS)
+#define USE_MATLAB_BLAS
+
+#elif defined (NBLAS)
+#define USE_NO_BLAS
+
+#elif defined (MATLAB_MEX_FILE)
+#define USE_MATLAB_BLAS
+
+#elif defined (CBLAS)
+#define USE_C_BLAS
+
+#elif defined (UMF_SOL2) && !defined (NSUNPERF)
+#define USE_SUNPERF_BLAS
+
+#elif defined (UMF_SGI) && !defined (NSCSL)
+#define USE_SCSL_BLAS
+
+#else
+#define USE_FORTRAN_BLAS
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* int vs. long integer arguments */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Determine if the BLAS exists for the long integer version.  It exists if
+    LONGBLAS is defined in the Makefile, or if using the BLAS from the
+    Sun Performance Library, or SGI's SCSL Scientific Library.
+*/
+
+#if defined (USE_SUNPERF_BLAS) || defined (USE_SCSL_BLAS)
+#ifndef LONGBLAS
+#define LONGBLAS
+#endif
+#endif
+
+/* do not use the BLAS if Int's are long and LONGBLAS is not defined */
+#if defined (LONG_INTEGER) && !defined (LONGBLAS) && !defined (USE_NO_BLAS)
+#define USE_NO_BLAS
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+/* Use (void *) arguments for the SGI */
+/* -------------------------------------------------------------------------- */
+
+#if defined (UMF_SGI)
+/*
+    Use (void *) pointers for complex types in SCSL.
+    The ATLAS C-BLAS, and the SGI C-BLAS differ.  The former uses (void *)
+    arguments, the latter uses SCSL_ZOMPLEX_T, which are either scsl_zomplex
+    or (void *).  Using (void *) is simpler, and is selected by defining
+    SCSL_VOID_ARGS, below.  The cc compiler doesn't complain, but gcc is
+    more picky, and generates a warning without this next statement.
+    With gcc and the 07/09/98 version of SGI's cblas.h, spurious warnings
+    about complex BLAS arguments will be reported anyway.  This is because this
+    older version of SGI's cblas.h does not make use of the SCSL_VOID_ARGS
+    parameter, which is present in the 12/6/01 version of SGI's cblas.h.  You
+    can safely ignore these warnings.
+*/
+#define SCSL_VOID_ARGS
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+/* The BLAS exists, construct appropriate macros */
+/* -------------------------------------------------------------------------- */
+
+#if !defined (USE_NO_BLAS)             /* { */
+
+/*
+    If the compile-time flag -DNBLAS is defined, then the BLAS are not used,
+    portable vanilla C code is used instead, and the remainder of this file
+    is ignored.
+
+    Using the BLAS is much faster, but how C calls the Fortran BLAS is
+    machine-dependent and thus can cause portability problems.  Thus, use
+    -DNBLAS to ensure portability (at the expense of speed).
+
+    Preferences:
+
+       *** The best interface to use, regardless of the option you select
+           below, is the standard C-BLAS interface.  Not all BLAS libraries
+           use this interface.  The only problem with this interface is that
+           it does not extend to the LP64 model.  The C-BLAS does not provide
+           for a 64-bit integer.  In addition, SGI's older cblas.h can cause
+           spurious warnings when using the C-BLAS interface.
+
+       1) often the most preferred (but see option (3)):  use the
+           optimized vendor-supplied library (such as the Sun Performance
+           Library, or IBM's ESSL).  This is often the fastest, but might not
+           be portable and might not always be available.  When compiling a
+           MATLAB mexFunction it might be difficult get the mex compiler
+           script to recognize the vendor- supplied BLAS.  Note that the
+           freely-available BLAS (option 3) can be faster than the vendor-
+           specific BLAS.  You are encourage to try both option (1) and (3).
+
+       2) When compiling the UMFPACK mexFunction to use UMFPACK in MATLAB, use
+           the BLAS provided by The Mathworks, Inc.  This assumes you are using
+           MATLAB V6 or higher, since the BLAS are not incorporated in V5 or
+           earlier versions.  On my Sun workstation, the MATLAB BLAS gave
+           slightly worse performance than the Sun Perf. BLAS.  The advantage
+           of using the MATLAB BLAS is that it's available on any computer that
+           has MATLAB V6 or higher.  I have not tried using MATLAB BLAS outside
+           of a mexFunction in a stand-alone C code, but MATLAB (V6) allows for
+           this.  This is well worth trying if you have MATLAB and don't want
+           to bother installing the ATLAS BLAS (option 3a, below).  The only
+           glitch to this is that MATLAB does not provide a portable interface
+           to the BLAS (an underscore is required for some but not all
+           architectures).  For Windows and MATLAB 6.0 or 6.1, you also need
+           to copy the libmwlapack.dll file into your MATLAB installation
+           directory; see the User Guide for details.
+
+           In the current distribution, the only BLAS that the UMFPACK
+           mexFunction will use is the internal MATLAB BLAS.  It's possible to
+           use other BLAS, but handling the porting of using the mex compiler
+           with different BLAS libraries is not trivial.
+
+           As of MATLAB 6.5, the BLAS used internally in MATLAB is the ATLAS
+           BLAS.
+
+       3) Use a freely-available high-performance BLAS library:
+
+           (a) The BLAS by Kazashige Goto and Robert van de Geijn, at
+               http://www.cs.utexas.edu/users/flame/goto.  This BLAS increased
+               the performance of UMFPACK by almost 50% as compared to the
+               ATLAS BLAS (v3.2).
+
+           (b) The ATLAS BLAS, available at http://www.netlib.org/atlas,
+               by R. Clint Whaley, Antoine Petitet, and Jack Dongarra.
+               This has a standard C interface, and thus the interface to it is
+               fully portable.  Its performance rivals, and sometimes exceeds,
+               the vendor-supplied BLAS on many computers.
+
+           (b) The Fortran RISC BLAS by Michel Dayde', Iain Duff, Antoine
+               Petitet, and Abderrahim Qrichi Aniba, available via anonymous
+               ftp to ftp.enseeiht.fr in the pub/numerique/BLAS/RISC directory,
+               See M. J. Dayde' and I. S. Duff, "The RISC BLAS:  A blocked
+               implementation of level 3 BLAS for RISC processors, ACM Trans.
+               Math. Software, vol. 25, no. 3., Sept. 1999.  This will give
+               you good performance, but with the same C-to-Fortran portability
+               problems as option (1).
+
+       4) Use UMFPACK's built-in vanilla C code by setting -DNBLAS at compile
+           time.  The key advantage is portability, which is guaranteed if you
+           have an ANSI C compliant compiler.  You also don't need to download
+           any other package - UMFPACK is stand-alone.  No Fortran is used
+           anywhere in UMFPACK.  UMFPACK will be much slower than when using
+           options (1) through (3), however.
+
+       5) least preferred:  use the standard Fortran implementation of the
+           BLAS, also available at Netlib (http://www.netlib.org/blas).  This
+           will be no faster than option (4), and not portable because of
+           C-to-Fortran calling conventions.  Don't bother trying option (5).
+
+    The mechanics of how C calls the BLAS on various computers are as follows:
+
+       * C-BLAS (from the ATLAS library, for example):
+           The same interface is used on all computers.
+
+       * Defaults for calling the Fortran BLAS:
+           add underscore, pass scalars by reference, use string arguments.
+
+       * The Fortran BLAS on Sun Solaris (when compiling the MATLAB mexFunction
+           or when using the Fortran RISC BLAS), SGI IRIX, Linux, and Compaq
+           Alpha: use defaults.
+
+       * Sun Solaris (when using the C-callable Sun Performance library):
+           no underscore, pass scalars by value, use character arguments.
+
+       * The Fortran BLAS (ESSL Library) on the IBM RS 6000, and HP Unix:
+           no underscore, pass scalars by reference, use string arguments.
+
+       * The Fortran BLAS on Windows:
+           no underscore, pass scalars by reference, use string arguments.
+           If you compile the umfpack mexFunction using umfpack_make, and are
+           using the lcc compiler bundled with MATLAB, then you must first
+           copy the umfpack\lcc_lib\libmwlapack.lib file into the
+           <matlab>\extern\lib\win32\lcc\ directory, where <matlab> is the
+           directory in which MATLAB is installed.  Next, type mex -setup
+           at the MATLAB prompt, and ask MATLAB to select the lcc compiler.
+           MATLAB has built-in BLAS, but it cannot be accessed by a program
+           compiled by lcc without first copying this file.
+*/
+
+
+
+/* -------------------------------------------------------------------------- */
+#ifdef USE_C_BLAS      /* { */
+/* -------------------------------------------------------------------------- */
+
+
+/* -------------------------------------------------------------------------- */
+/* use the C-BLAS (any computer) */
+/* -------------------------------------------------------------------------- */
+
+/*
+    C-BLAS is the default interface, with the following exceptions.  Solaris
+    uses the Sun Performance BLAS for libumfpack.a (the C-callable library).
+    SGI IRIX uses the SCSL BLAS for libumfpack.a.  All architectures use
+    MATLAB's internal BLAS for the mexFunction on any architecture.  These
+    options are set in the Make.* files.  The Make.generic file uses no BLAS
+    at all.
+
+    If you use the ATLAS C-BLAS, then be sure to set the -I flag to
+    -I/path/ATLAS/include, where /path/ATLAS is the ATLAS installation
+    directory.  See Make.solaris for an example.  You do not need to do this
+    for the SGI, which has a /usr/include/cblas.h.
+*/
+
+#include "cblas.h"
+
+#ifdef COMPLEX
+#define BLAS_GEMM_ROUTINE cblas_zgemm
+#define BLAS_TRSM_ROUTINE cblas_ztrsm
+#define BLAS_TRSV_ROUTINE cblas_ztrsv
+#define BLAS_GEMV_ROUTINE cblas_zgemv
+#define BLAS_GER_ROUTINE  cblas_zgeru
+#define BLAS_SCAL_ROUTINE cblas_zscal
+#define BLAS_COPY_ROUTINE cblas_zcopy
+#define BLAS_DECLARE_SCALAR(x) double x [2]
+#define BLAS_ASSIGN(x,xr,xi) { x [0] = xr ; x [1] = xi ; }
+#else
+#define BLAS_GEMM_ROUTINE cblas_dgemm
+#define BLAS_TRSM_ROUTINE cblas_dtrsm
+#define BLAS_TRSV_ROUTINE cblas_dtrsv
+#define BLAS_GEMV_ROUTINE cblas_dgemv
+#define BLAS_GER_ROUTINE  cblas_dger
+#define BLAS_SCAL_ROUTINE cblas_dscal
+#define BLAS_COPY_ROUTINE cblas_dcopy
+#define BLAS_DECLARE_SCALAR(x) double x
+#define BLAS_ASSIGN(x,xr,xi) { x = xr ; }
+#endif
+
+#define BLAS_LOWER CblasLower
+#define BLAS_UNIT_DIAGONAL CblasUnit
+#define BLAS_RIGHT CblasRight
+#define BLAS_NO_TRANSPOSE CblasNoTrans
+#define BLAS_TRANSPOSE CblasTrans
+#define BLAS_COLUMN_MAJOR_ORDER CblasColMajor,
+#define BLAS_SCALAR(x) x
+#define BLAS_INT_SCALAR(n) n
+#define BLAS_ARRAY(a) a
+
+
+
+/* -------------------------------------------------------------------------- */
+#else  /* } USE_C_BLAS { */
+/* -------------------------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* use Fortran (or other architecture-specific) BLAS */
+/* -------------------------------------------------------------------------- */
+
+/* No such argument when not using the C-BLAS */
+#define BLAS_COLUMN_MAJOR_ORDER
+
+/* Determine which architecture we're on and set options accordingly. */
+/* The default, if nothing is defined is to add an underscore, */
+/* pass scalars by reference, and use string arguments. */
+
+/* ---------------------------------- */
+/* Sun Performance BLAS */
+/* ---------------------------------- */
+
+#ifdef USE_SUNPERF_BLAS
+#ifdef _SUNPERF_H
+/* <sunperf.h> has been included somehow anyway, outside of umf_config.h */
+#error "sunperf.h must NOT be #include'd.  See umf_config.h for details."
+#endif
+#define BLAS_BY_VALUE
+#define BLAS_NO_UNDERSCORE
+#define BLAS_CHAR_ARG
+#endif /* USE_SUNPERF_BLAS */
+
+/* ---------------------------------- */
+/* SGI SCSL BLAS */
+/* ---------------------------------- */
+
+#ifdef USE_SCSL_BLAS
+#if defined (LP64)
+#include <scsl_blas_i8.h>
+#else
+#include <scsl_blas.h>
+#endif
+#define BLAS_BY_VALUE
+#define BLAS_NO_UNDERSCORE
+#endif /* USE_SCSL_BLAS */
+
+/* ---------------------------------- */
+/* IBM AIX, Windows, and HP Fortran BLAS */
+/* ---------------------------------- */
+
+#if defined (UMF_AIX) || defined (UMF_WINDOWS) || defined (UMF_HP)
+#define BLAS_NO_UNDERSCORE
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+/* BLAS names */
+/* -------------------------------------------------------------------------- */
+
+#if defined (LP64) && defined (USE_SUNPERF_BLAS) && defined (LONG_INTEGER)
+
+/* 64-bit sunperf BLAS, for Sun Solaris only */
+#ifdef COMPLEX
+#define BLAS_GEMM_ROUTINE zgemm_64
+#define BLAS_TRSM_ROUTINE ztrsm_64
+#define BLAS_TRSV_ROUTINE ztrsv_64
+#define BLAS_GEMV_ROUTINE zgemv_64
+#define BLAS_GER_ROUTINE  zgeru_64
+#define BLAS_SCAL_ROUTINE zscal_64
+#define BLAS_COPY_ROUTINE zcopy_64
+#else
+#define BLAS_GEMM_ROUTINE dgemm_64
+#define BLAS_TRSM_ROUTINE dtrsm_64
+#define BLAS_TRSV_ROUTINE dtrsv_64
+#define BLAS_GEMV_ROUTINE dgemv_64
+#define BLAS_GER_ROUTINE  dger_64
+#define BLAS_SCAL_ROUTINE dscal_64
+#define BLAS_COPY_ROUTINE dcopy_64
+#endif /* COMPLEX */
+
+#else
+
+#ifdef COMPLEX
+
+/* naming convention (use underscore, or not) */
+#ifdef BLAS_NO_UNDERSCORE
+#define BLAS_GEMM_ROUTINE zgemm
+#define BLAS_TRSM_ROUTINE ztrsm
+#define BLAS_TRSV_ROUTINE ztrsv
+#define BLAS_GEMV_ROUTINE zgemv
+#define BLAS_GER_ROUTINE  zgeru
+#define BLAS_SCAL_ROUTINE zscal
+#define BLAS_COPY_ROUTINE zcopy
+#else
+/* default:  add underscore */
+#define BLAS_GEMM_ROUTINE zgemm_
+#define BLAS_TRSM_ROUTINE ztrsm_
+#define BLAS_TRSV_ROUTINE ztrsv_
+#define BLAS_GEMV_ROUTINE zgemv_
+#define BLAS_GER_ROUTINE  zgeru_
+#define BLAS_SCAL_ROUTINE zscal_
+#define BLAS_COPY_ROUTINE zcopy_
+#endif
+
+#else
+
+/* naming convention (use underscore, or not) */
+#ifdef BLAS_NO_UNDERSCORE
+#define BLAS_GEMM_ROUTINE dgemm
+#define BLAS_TRSM_ROUTINE dtrsm
+#define BLAS_TRSV_ROUTINE dtrsv
+#define BLAS_GEMV_ROUTINE dgemv
+#define BLAS_GER_ROUTINE  dger
+#define BLAS_SCAL_ROUTINE dscal
+#define BLAS_COPY_ROUTINE dcopy
+#else
+/* default:  add underscore */
+#define BLAS_GEMM_ROUTINE dgemm_
+#define BLAS_TRSM_ROUTINE dtrsm_
+#define BLAS_TRSV_ROUTINE dtrsv_
+#define BLAS_GEMV_ROUTINE dgemv_
+#define BLAS_GER_ROUTINE  dger_
+#define BLAS_SCAL_ROUTINE dscal_
+#define BLAS_COPY_ROUTINE dcopy_
+#endif
+
+#endif /* COMPLEX */
+
+#endif /* LP64 && USE_SUNPERF_BLAS */
+
+
+/* -------------------------------------------------------------------------- */
+/* BLAS real or complex floating-point scalars */
+/* -------------------------------------------------------------------------- */
+
+#ifdef COMPLEX
+
+/*
+    The SunPerf BLAS expects to see a doublecomplex scalar, but it
+    also will accept an array of size 2.  See the manual, normally at
+    file:///opt/SUNWspro/WS6U1/lib/locale/C/html/manuals/perflib/user_guide
+    /plug_using_perflib.html .  This manual is inconsistent with the man pages
+    for zgemm, zgemv, and zgeru and also inconsistent with the <sunperf.h>
+    include file.  Use this instead, for SunPerf (only works if you do NOT
+    include sunperf.h).  Fortunately, this file (umf_config.h) is not included
+    in any user code that calls UMFPACK.  Thus, the caller may include
+    sunperf.h in his or her own code, and that is safely ignored here.
+    SGI's SCSL BLAS has yet a different kind of struct, but we can use a
+    double array of size 2 instead (since SCSL_VOID_ARGS is defined).
+    Most BLAS expect complex scalars as pointers to double arrays of size 2.
+*/
+
+#define BLAS_DECLARE_SCALAR(x) double x [2]
+#define BLAS_ASSIGN(x,xr,xi) { x [0] = xr ; x [1] = xi ; }
+#define BLAS_SCALAR(x) x
+
+#else
+
+#define BLAS_DECLARE_SCALAR(x) double x
+#define BLAS_ASSIGN(x,xr,xi) { x = xr ; }
+#ifdef BLAS_BY_VALUE
+#define BLAS_SCALAR(x) x
+#else
+#define BLAS_SCALAR(x) &(x)
+#endif
+
+#endif /* COMPLEX */
+
+
+/* -------------------------------------------------------------------------- */
+/* BLAS integer scalars */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Fortran requires integers to be passed by reference.
+    The SCSL BLAS requires long long arguments in LP64 mode.
+*/
+
+#if defined (USE_SCSL_BLAS) && defined (LP64)
+#define BLAS_INT_SCALAR(n) ((long long) n)
+#else
+#ifdef BLAS_BY_VALUE
+#define BLAS_INT_SCALAR(n) n
+#else
+#define BLAS_INT_SCALAR(n) &(n)
+#endif
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+/* BLAS strings */
+/* -------------------------------------------------------------------------- */
+
+/*
+    The Sun Performance BLAS wants a character instead of a string.
+*/
+
+#ifdef BLAS_CHAR_ARG
+#define BLAS_NO_TRANSPOSE 'N'
+#define BLAS_TRANSPOSE 'T'
+#define BLAS_LEFT 'L'
+#define BLAS_RIGHT 'R'
+#define BLAS_LOWER 'L'
+#define BLAS_UNIT_DIAGONAL 'U'
+#else
+#define BLAS_NO_TRANSPOSE "N"
+#define BLAS_TRANSPOSE "T"
+#define BLAS_LEFT "L"
+#define BLAS_RIGHT "R"
+#define BLAS_LOWER "L"
+#define BLAS_UNIT_DIAGONAL "U"
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+/* BLAS arrays */
+/* -------------------------------------------------------------------------- */
+
+/*
+    The complex SunPerf BLAS expects to see a doublecomplex array of size s.
+    This is broken (see above, regarding complex scalars in sunperf.h).
+    For SunPerf BLAS, just pass a pointer to the array, and ignore sunperf.h.
+    With sunperf.h, you would need:
+
+       #define BLAS_ARRAY(a) ((doublecomplex *)(a))
+
+    SGI's SCSL BLAS has yet a different kind of struct, but we can use a
+    double array of size 2 instead (since SCSL_VOID_ARGS is defined).
+
+    The real versions all use just a (double *) pointer.
+
+    In all cases, no typecast is required.  This will break if <sunperf.h> is
+    included.
+
+    If you have read this far, I hope you see now why (void *) a much better
+    choice for complex BLAS prototypes, and why double x [2] is better than
+    an architecture dependent struct { double real ; double imag ; }
+    type definition.
+
+*/
+
+#define BLAS_ARRAY(a) (a)
+
+
+/* -------------------------------------------------------------------------- */
+#endif /* USE_C_BLAS } */
+/* -------------------------------------------------------------------------- */
+
+
+
+
+
+/* -------------------------------------------------------------------------- */
+/* BLAS macros, for all interfaces */
+/* -------------------------------------------------------------------------- */
+
+/*
+   All architecture dependent issues have now been taken into consideration,
+   and folded into the macros BLAS_DECLARE_SCALAR, BLAS_ASSIGN, BLAS_*_ROUTINE,
+   BLAS_COLUMN_MAJOR_ORDER, BLAS_NO_TRANSPOSE, BLAS_TRANSPOSE, BLAS_SCALAR,
+   BLAS_INT_SCALAR, BLAS_ARRAY, and Int.
+
+   You will note that there is not a *** single *** name, declaration, or
+   argument to the BLAS which is not somehow different in one or more versions
+   of the BLAS!
+*/
+
+
+/* C = C - A*B', where:
+ * A is m-by-k with leading dimension ldac
+ * B is k-by-n with leading dimension ldb
+ * C is m-by-n with leading dimension ldac */
+#define BLAS_GEMM(m,n,k,A,B,ldb,C,ldac) \
+{ \
+    BLAS_DECLARE_SCALAR (alpha) ; \
+    BLAS_DECLARE_SCALAR (beta) ; \
+    BLAS_ASSIGN (alpha, -1.0, 0.0) ; \
+    BLAS_ASSIGN (beta, 1.0, 0.0) ; \
+    (void) BLAS_GEMM_ROUTINE (BLAS_COLUMN_MAJOR_ORDER \
+       BLAS_NO_TRANSPOSE, BLAS_TRANSPOSE, \
+       BLAS_INT_SCALAR (m), BLAS_INT_SCALAR (n), BLAS_INT_SCALAR (k), \
+       BLAS_SCALAR (alpha), \
+       BLAS_ARRAY (A), BLAS_INT_SCALAR (ldac), \
+       BLAS_ARRAY (B), BLAS_INT_SCALAR (ldb), BLAS_SCALAR (beta), \
+       BLAS_ARRAY (C), BLAS_INT_SCALAR (ldac)) ; \
+}
+
+/* A = A - x*y', where:
+ * A is m-by-n with leading dimension d
+   x is a column vector with stride 1
+   y is a column vector with stride 1 */
+#define BLAS_GER(m,n,x,y,A,d) \
+{ \
+    Int one = 1 ; \
+    BLAS_DECLARE_SCALAR (alpha) ; \
+    BLAS_ASSIGN (alpha, -1.0, 0.0) ; \
+    (void) BLAS_GER_ROUTINE (BLAS_COLUMN_MAJOR_ORDER \
+       BLAS_INT_SCALAR (m), BLAS_INT_SCALAR (n), \
+       BLAS_SCALAR (alpha), \
+       BLAS_ARRAY (x), BLAS_INT_SCALAR (one), \
+       BLAS_ARRAY (y), BLAS_INT_SCALAR (one), \
+       BLAS_ARRAY (A), BLAS_INT_SCALAR (d)) ; \
+}
+
+/* y = y - A*x, where A is m-by-n with leading dimension d,
+   x is a column vector with stride 1
+   y is a column vector with stride 1 */
+#define BLAS_GEMV(m,n,A,x,y,d) \
+{ \
+    Int one = 1 ; \
+    BLAS_DECLARE_SCALAR (alpha) ; \
+    BLAS_DECLARE_SCALAR (beta) ; \
+    BLAS_ASSIGN (alpha, -1.0, 0.0) ; \
+    BLAS_ASSIGN (beta, 1.0, 0.0) ; \
+    (void) BLAS_GEMV_ROUTINE (BLAS_COLUMN_MAJOR_ORDER \
+       BLAS_NO_TRANSPOSE, \
+       BLAS_INT_SCALAR (m), BLAS_INT_SCALAR (n), \
+       BLAS_SCALAR (alpha), \
+       BLAS_ARRAY (A), BLAS_INT_SCALAR (d), \
+       BLAS_ARRAY (x), BLAS_INT_SCALAR (one), BLAS_SCALAR (beta), \
+       BLAS_ARRAY (y), BLAS_INT_SCALAR (one)) ; \
+}
+
+
+/* solve Lx=b, where:
+ * B is a column vector (m-by-1) with leading dimension d
+ * A is m-by-m with leading dimension d */
+#define BLAS_TRSV(m,A,b,d) \
+{ \
+    Int one = 1 ; \
+    (void) BLAS_TRSV_ROUTINE (BLAS_COLUMN_MAJOR_ORDER \
+       BLAS_LOWER, BLAS_NO_TRANSPOSE, BLAS_UNIT_DIAGONAL, \
+       BLAS_INT_SCALAR (m), \
+       BLAS_ARRAY (A), BLAS_INT_SCALAR (d), \
+       BLAS_ARRAY (b), BLAS_INT_SCALAR (one)) ; \
+}
+
+/* solve XL'=B where:
+ * B is m-by-n with leading dimension ldb
+ * A is n-by-n with leading dimension lda */
+#define BLAS_TRSM_RIGHT(m,n,A,lda,B,ldb) \
+{ \
+    BLAS_DECLARE_SCALAR (alpha) ; \
+    BLAS_ASSIGN (alpha, 1.0, 0.0) ; \
+    (void) BLAS_TRSM_ROUTINE (BLAS_COLUMN_MAJOR_ORDER \
+       BLAS_RIGHT, BLAS_LOWER, BLAS_TRANSPOSE, BLAS_UNIT_DIAGONAL, \
+       BLAS_INT_SCALAR (m), BLAS_INT_SCALAR (n), \
+       BLAS_SCALAR (alpha), \
+       BLAS_ARRAY (A), BLAS_INT_SCALAR (lda), \
+       BLAS_ARRAY (B), BLAS_INT_SCALAR (ldb)) ; \
+}
+
+/* x = s*x, where x is a stride-1 vector of length n */
+#define BLAS_SCAL(n,s,x) \
+{ \
+    Int one = 1 ; \
+    BLAS_DECLARE_SCALAR (alpha) ; \
+    BLAS_ASSIGN (alpha, REAL_COMPONENT (s), IMAG_COMPONENT (s)) ; \
+    (void) BLAS_SCAL_ROUTINE ( \
+       BLAS_INT_SCALAR (n), BLAS_SCALAR (alpha), \
+       BLAS_ARRAY (x), BLAS_INT_SCALAR (one)) ; \
+}
+
+/* x = y, where x and y are a stride-1 vectors of length n */
+#define BLAS_COPY(n,x,y) \
+{ \
+    Int one = 1 ; \
+    (void) BLAS_COPY_ROUTINE ( \
+       BLAS_INT_SCALAR (n), \
+       BLAS_ARRAY (x), BLAS_INT_SCALAR (one), \
+       BLAS_ARRAY (y), BLAS_INT_SCALAR (one)) ; \
+}
+
+#endif /* !defined (USE_NO_BLAS) } */
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_create_element.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_create_element.c
new file mode 100644 (file)
index 0000000..48b1d59
--- /dev/null
@@ -0,0 +1,605 @@
+/* ========================================================================== */
+/* === UMF_create_element =================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Factorization of a frontal matrix is complete.  Create a new element for
+    later assembly into a subsequent frontal matrix.  Returns TRUE if
+    successful, FALSE if out of memory.
+*/
+
+#include "umf_internal.h"
+#include "umf_mem_alloc_element.h"
+#include "umf_mem_alloc_tail_block.h"
+#include "umf_mem_free_tail_block.h"
+#include "umf_get_memory.h"
+
+/* ========================================================================== */
+/* === copy_column ========================================================== */
+/* ========================================================================== */
+
+PRIVATE void copy_column (Int len, Entry *X, Entry *Y)
+{
+    Int i ;
+#pragma ivdep
+    for (i = 0 ; i < len ; i++)
+    {
+       Y [i] = X [i] ;
+    }
+}
+
+/* ========================================================================== */
+/* === UMF_create_element =================================================== */
+/* ========================================================================== */
+
+GLOBAL Int UMF_create_element
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    SymbolicType *Symbolic
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int j, col, row, *Fcols, *Frows, fnrows, fncols, *Cols, len, needunits, t1,
+       t2, size, e, i, *E, *Fcpos, *Frpos, *Rows, eloc, fnr_curr, f,
+       got_memory, *Row_tuples, *Row_degree, *Row_tlen, *Col_tuples, max_mark,
+       *Col_degree, *Col_tlen, nn, n_row, n_col, r2, c2, do_Fcpos ;
+    Entry *C, *Fcol ;
+    Element *ep ;
+    Unit *p, *Memory ;
+    Tuple *tp, *tp1, *tp2, tuple, *tpend ;
+#ifndef NDEBUG
+    DEBUG2 (("FRONTAL WRAPUP\n")) ;
+    UMF_dump_current_front (Numeric, Work, TRUE) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (Work->fnpiv == 0) ;
+    ASSERT (Work->fnzeros == 0) ;
+    Row_degree = Numeric->Rperm ;
+    Row_tuples = Numeric->Uip ;
+    Row_tlen   = Numeric->Uilen ;
+    Col_degree = Numeric->Cperm ;
+    Col_tuples = Numeric->Lip ;
+    Col_tlen   = Numeric->Lilen ;
+    n_row = Work->n_row ;
+    n_col = Work->n_col ;
+    nn = MAX (n_row, n_col) ;
+    Fcols = Work->Fcols ;
+    Frows = Work->Frows ;
+    Fcpos = Work->Fcpos ;
+    Frpos = Work->Frpos ;
+    Memory = Numeric->Memory ;
+    fncols = Work->fncols ;
+    fnrows = Work->fnrows ;
+
+    tp = (Tuple *) NULL ;
+    tp1 = (Tuple *) NULL ;
+    tp2 = (Tuple *) NULL ;
+
+    /* ---------------------------------------------------------------------- */
+    /* add the current frontal matrix to the degrees of each column */
+    /* ---------------------------------------------------------------------- */
+
+    if (!Symbolic->fixQ)
+    {
+       /* but only if the column ordering is not fixed */
+#pragma ivdep
+       for (j = 0 ; j < fncols ; j++)
+       {
+           /* add the current frontal matrix to the degree */
+           ASSERT (Fcols [j] >= 0 && Fcols [j] < n_col) ;
+           Col_degree [Fcols [j]] += fnrows ;
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* add the current frontal matrix to the degrees of each row */
+    /* ---------------------------------------------------------------------- */
+
+#pragma ivdep
+    for (i = 0 ; i < fnrows ; i++)
+    {
+       /* add the current frontal matrix to the degree */
+       ASSERT (Frows [i] >= 0 && Frows [i] < n_row) ;
+       Row_degree [Frows [i]] += fncols ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* Reset the external degree counters */
+    /* ---------------------------------------------------------------------- */
+
+    E = Work->E ;
+    max_mark = MAX_MARK (nn) ;
+
+    if (!Work->pivcol_in_front)
+    {
+       /* clear the external column degrees. no more Usons of current front */
+       Work->cdeg0 += (nn + 1) ;
+       if (Work->cdeg0 >= max_mark)
+       {
+           /* guard against integer overflow.  This is very rare */
+           DEBUG1 (("Integer overflow, cdeg\n")) ;
+           Work->cdeg0 = 1 ;
+#pragma ivdep
+           for (e = 1 ; e <= Work->nel ; e++)
+           {
+               if (E [e])
+               {
+                   ep = (Element *) (Memory + E [e]) ;
+                   ep->cdeg = 0 ;
+               }
+           }
+       }
+    }
+
+    if (!Work->pivrow_in_front)
+    {
+       /* clear the external row degrees.  no more Lsons of current front */
+       Work->rdeg0 += (nn + 1) ;
+       if (Work->rdeg0 >= max_mark)
+       {
+           /* guard against integer overflow.  This is very rare */
+           DEBUG1 (("Integer overflow, rdeg\n")) ;
+           Work->rdeg0 = 1 ;
+#pragma ivdep
+           for (e = 1 ; e <= Work->nel ; e++)
+           {
+               if (E [e])
+               {
+                   ep = (Element *) (Memory + E [e]) ;
+                   ep->rdeg = 0 ;
+               }
+           }
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* clear row/col offsets */
+    /* ---------------------------------------------------------------------- */
+
+    if (!Work->pivrow_in_front)
+    {
+#pragma ivdep
+       for (j = 0 ; j < fncols ; j++)
+       {
+           Fcpos [Fcols [j]] = EMPTY ;
+       }
+    }
+
+    if (!Work->pivcol_in_front)
+    {
+#pragma ivdep
+       for (i = 0 ; i < fnrows ; i++)
+       {
+           Frpos [Frows [i]] = EMPTY ;
+       }
+    }
+
+    if (fncols <= 0 || fnrows <= 0)
+    {
+       /* no element to create */
+       DEBUG2 (("Element evaporation\n")) ;
+       Work->prior_element = EMPTY ;
+       return (TRUE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* create element for later assembly */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    UMF_allocfail = FALSE ;
+    if (UMF_gprob > 0)
+    {
+       double rrr = ((double) (rand ( ))) / (((double) RAND_MAX) + 1) ;
+       DEBUG4 (("Check random %e %e\n", rrr, UMF_gprob)) ;
+       UMF_allocfail = rrr < UMF_gprob ;
+       if (UMF_allocfail) DEBUGm2 (("Random garbage collection (create)\n"));
+    }
+#endif
+
+    needunits = 0 ;
+    got_memory = FALSE ;
+    eloc = UMF_mem_alloc_element (Numeric, fnrows, fncols, &Rows, &Cols, &C,
+       &needunits, &ep) ;
+
+    /* if UMF_get_memory needs to be called */
+    if (Work->do_grow)
+    {
+       /* full compaction of current frontal matrix, since UMF_grow_front will
+        * be called next anyway. */
+       r2 = fnrows ;
+       c2 = fncols ;
+       do_Fcpos = FALSE ;
+    }
+    else
+    {
+       /* partial compaction. */
+       r2 = MAX (fnrows, Work->fnrows_new + 1) ;
+       c2 = MAX (fncols, Work->fncols_new + 1) ;
+       /* recompute Fcpos if pivot row is in the front */
+       do_Fcpos = Work->pivrow_in_front ;
+    }
+
+    if (!eloc)
+    {
+       /* Do garbage collection, realloc, and try again. */
+       /* Compact the current front if it needs to grow anyway. */
+       /* Note that there are no pivot rows or columns in the current front */
+       DEBUGm3 (("get_memory from umf_create_element, 1\n")) ;
+       if (!UMF_get_memory (Numeric, Work, needunits, r2, c2, do_Fcpos))
+       {
+           /* :: out of memory in umf_create_element (1) :: */
+           DEBUGm4 (("out of memory: create element (1)\n")) ;
+           return (FALSE) ;    /* out of memory */
+       }
+       got_memory = TRUE ;
+       Memory = Numeric->Memory ;
+       eloc = UMF_mem_alloc_element (Numeric, fnrows, fncols, &Rows, &Cols, &C,
+           &needunits, &ep) ;
+       ASSERT (eloc >= 0) ;
+       if (!eloc)
+       {
+           /* :: out of memory in umf_create_element (2) :: */
+           DEBUGm4 (("out of memory: create element (2)\n")) ;
+           return (FALSE) ;    /* out of memory */
+       }
+    }
+
+    e = ++(Work->nel) ;        /* get the name of this new frontal matrix */
+    Work->prior_element = e ;
+    DEBUG8 (("wrapup e "ID" nel "ID"\n", e, Work->nel)) ;
+
+    ASSERT (e > 0 && e < Work->elen) ;
+    ASSERT (E [e] == 0) ;
+    E [e] = eloc ;
+
+    if (Work->pivcol_in_front)
+    {
+       /* the new element is a Uson of the next frontal matrix */
+       ep->cdeg = Work->cdeg0 ;
+    }
+
+    if (Work->pivrow_in_front)
+    {
+       /* the new element is an Lson of the next frontal matrix */
+       ep->rdeg = Work->rdeg0 ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* copy frontal matrix into the new element */
+    /* ---------------------------------------------------------------------- */
+
+#pragma ivdep
+    for (i = 0 ; i < fnrows ; i++)
+    {
+       Rows [i] = Frows [i] ;
+    }
+#pragma ivdep
+    for (i = 0 ; i < fncols ; i++)
+    {
+       Cols [i] = Fcols [i] ;
+    }
+    Fcol = Work->Fcblock ;
+    DEBUG0 (("copy front "ID" by "ID"\n", fnrows, fncols)) ;
+    fnr_curr = Work->fnr_curr ;
+    ASSERT (fnr_curr >= 0 && fnr_curr % 2 == 1) ;
+    for (j = 0 ; j < fncols ; j++)
+    {
+       copy_column (fnrows, Fcol, C) ;
+#if 0
+#ifdef USE_NO_BLAS
+       copy_column (fnrows, Fcol, C) ;
+#else
+       could also use BLAS-COPY (fnrows, Fcol, C) here, but it is typically
+       not as fast as the inlined copy_column subroutine, above.
+#endif
+       for (i = 0 ; i < fnrows ; i++)
+       {
+           C [i] = Fcol [i] ;
+       }
+#endif
+       Fcol += fnr_curr ;
+       C += fnrows ;
+    }
+
+    DEBUG8 (("element copied\n")) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* add tuples for the new element */
+    /* ---------------------------------------------------------------------- */
+
+    tuple.e = e ;
+
+    if (got_memory)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* UMF_get_memory ensures enough space exists for each new tuple */
+       /* ------------------------------------------------------------------ */
+
+       /* place (e,f) in the element list of each column */
+       for (tuple.f = 0 ; tuple.f < fncols ; tuple.f++)
+       {
+           col = Fcols [tuple.f] ;
+           ASSERT (col >= 0 && col < n_col) ;
+           ASSERT (NON_PIVOTAL_COL (col)) ;
+           ASSERT (Col_tuples [col]) ;
+           tp = ((Tuple *) (Memory + Col_tuples [col])) + Col_tlen [col]++ ;
+           *tp = tuple ;
+       }
+
+       /* ------------------------------------------------------------------ */
+
+       /* place (e,f) in the element list of each row */
+       for (tuple.f = 0 ; tuple.f < fnrows ; tuple.f++)
+       {
+           row = Frows [tuple.f] ;
+           ASSERT (row >= 0 && row < n_row) ;
+           ASSERT (NON_PIVOTAL_ROW (row)) ;
+           ASSERT (Row_tuples [row]) ;
+           tp = ((Tuple *) (Memory + Row_tuples [row])) + Row_tlen [row]++ ;
+           *tp = tuple ;
+       }
+
+    }
+    else
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* place (e,f) in the element list of each column */
+       /* ------------------------------------------------------------------ */
+
+       /* might not have enough space for each tuple */
+
+       for (tuple.f = 0 ; tuple.f < fncols ; tuple.f++)
+       {
+           col = Fcols [tuple.f] ;
+           ASSERT (col >= 0 && col < n_col) ;
+           ASSERT (NON_PIVOTAL_COL (col)) ;
+           t1 = Col_tuples [col] ;
+           DEBUG1 (("Placing on col:"ID" , tuples at "ID"\n",
+               col, Col_tuples [col])) ;
+
+           size = 0 ;
+           len = 0 ;
+
+           if (t1)
+           {
+               p = Memory + t1 ;
+               tp = (Tuple *) p ;
+               size = GET_BLOCK_SIZE (p) ;
+               len = Col_tlen [col] ;
+               tp2 = tp + len ;
+           }
+
+           needunits = UNITS (Tuple, len + 1) ;
+           DEBUG1 (("len: "ID" size: "ID" needunits: "ID"\n",
+               len, size, needunits));
+
+           if (needunits > size && t1)
+           {
+               /* prune the tuples */
+               tp1 = tp ;
+               tp2 = tp ;
+               tpend = tp + len ;
+               for ( ; tp < tpend ; tp++)
+               {
+                   e = tp->e ;
+                   ASSERT (e > 0 && e <= Work->nel) ;
+                   if (!E [e]) continue ;   /* element already deallocated */
+                   f = tp->f ;
+                   p = Memory + E [e] ;
+                   ep = (Element *) p ;
+                   p += UNITS (Element, 1) ;
+                   Cols = (Int *) p ;
+                   ;
+                   if (Cols [f] == EMPTY) continue ;   /* already assembled */
+                   ASSERT (col == Cols [f]) ;
+                   *tp2++ = *tp ;      /* leave the tuple in the list */
+               }
+               len = tp2 - tp1 ;
+               Col_tlen [col] = len ;
+               needunits = UNITS (Tuple, len + 1) ;
+           }
+
+           if (needunits > size)
+           {
+               /* no room exists - reallocate elsewhere */
+               DEBUG1 (("REALLOCATE Col: "ID", size "ID" to "ID"\n",
+                   col, size, 2*needunits)) ;
+
+#ifndef NDEBUG
+               UMF_allocfail = FALSE ;
+               if (UMF_gprob > 0)  /* a double relop, but ignore NaN case */
+               {
+                   double rrr = ((double) (rand ( ))) /
+                       (((double) RAND_MAX) + 1) ;
+                   DEBUG1 (("Check random %e %e\n", rrr, UMF_gprob)) ;
+                   UMF_allocfail = rrr < UMF_gprob ;
+                   if (UMF_allocfail) DEBUGm2 (("Random gar. (col tuple)\n")) ;
+               }
+#endif
+
+               needunits = MIN (2*needunits, (Int) UNITS (Tuple, nn)) ;
+               t2 = UMF_mem_alloc_tail_block (Numeric, needunits) ;
+               if (!t2)
+               {
+                   /* :: get memory in umf_create_element (1) :: */
+                   /* get memory, reconstruct all tuple lists, and return */
+                   /* Compact the current front if it needs to grow anyway. */
+                   /* Note: no pivot rows or columns in the current front */
+                   DEBUGm4 (("get_memory from umf_create_element, 1\n")) ;
+                   return (UMF_get_memory (Numeric, Work, 0, r2, c2,do_Fcpos));
+               }
+               Col_tuples [col] = t2 ;
+               tp2 = (Tuple *) (Memory + t2) ;
+               if (t1)
+               {
+                   for (i = 0 ; i < len ; i++)
+                   {
+                       *tp2++ = *tp1++ ;
+                   }
+                   UMF_mem_free_tail_block (Numeric, t1) ;
+               }
+           }
+
+           /* place the new (e,f) tuple in the element list of the column */
+           Col_tlen [col]++ ;
+           *tp2 = tuple ;
+       }
+
+       /* ------------------------------------------------------------------ */
+       /* place (e,f) in the element list of each row */
+       /* ------------------------------------------------------------------ */
+
+       for (tuple.f = 0 ; tuple.f < fnrows ; tuple.f++)
+       {
+           row = Frows [tuple.f] ;
+           ASSERT (row >= 0 && row < n_row) ;
+           ASSERT (NON_PIVOTAL_ROW (row)) ;
+           t1 = Row_tuples [row] ;
+           DEBUG1 (("Placing on row:"ID" , tuples at "ID"\n",
+               row, Row_tuples [row])) ;
+
+           size = 0 ;
+           len = 0 ;
+           if (t1)
+           {
+               p = Memory + t1 ;
+               tp = (Tuple *) p ;
+               size = GET_BLOCK_SIZE (p) ;
+               len = Row_tlen [row] ;
+               tp2 = tp + len ;
+           }
+
+           needunits = UNITS (Tuple, len + 1) ;
+           DEBUG1 (("len: "ID" size: "ID" needunits: "ID"\n",
+               len, size, needunits)) ;
+
+           if (needunits > size && t1)
+           {
+               /* prune the tuples */
+               tp1 = tp ;
+               tp2 = tp ;
+               tpend = tp + len ;
+               for ( ; tp < tpend ; tp++)
+               {
+                   e = tp->e ;
+                   ASSERT (e > 0 && e <= Work->nel) ;
+                   if (!E [e])
+                   {
+                       continue ;      /* element already deallocated */
+                   }
+                   f = tp->f ;
+                   p = Memory + E [e] ;
+                   ep = (Element *) p ;
+                   p += UNITS (Element, 1) ;
+                   Cols = (Int *) p ;
+                   Rows = Cols + (ep->ncols) ;
+                   if (Rows [f] == EMPTY) continue ;   /* already assembled */
+                   ASSERT (row == Rows [f]) ;
+                   *tp2++ = *tp ;      /* leave the tuple in the list */
+               }
+               len = tp2 - tp1 ;
+               Row_tlen [row] = len ;
+               needunits = UNITS (Tuple, len + 1) ;
+           }
+
+           if (needunits > size)
+           {
+               /* no room exists - reallocate elsewhere */
+               DEBUG1 (("REALLOCATE Row: "ID", size "ID" to "ID"\n",
+                   row, size, 2*needunits)) ;
+
+#ifndef NDEBUG
+               UMF_allocfail = FALSE ;
+               if (UMF_gprob > 0)  /* a double relop, but ignore NaN case */
+               {
+                   double rrr = ((double) (rand ( ))) /
+                       (((double) RAND_MAX) + 1) ;
+                   DEBUG1 (("Check random %e %e\n", rrr, UMF_gprob)) ;
+                   UMF_allocfail = rrr < UMF_gprob ;
+                   if (UMF_allocfail) DEBUGm2 (("Random gar. (row tuple)\n")) ;
+               }
+#endif
+
+               needunits = MIN (2*needunits, (Int) UNITS (Tuple, nn)) ;
+               t2 = UMF_mem_alloc_tail_block (Numeric, needunits) ;
+               if (!t2)
+               {
+                   /* :: get memory in umf_create_element (2) :: */
+                   /* get memory, reconstruct all tuple lists, and return */
+                   /* Compact the current front if it needs to grow anyway. */
+                   /* Note: no pivot rows or columns in the current front */
+                   DEBUGm4 (("get_memory from umf_create_element, 2\n")) ;
+                   return (UMF_get_memory (Numeric, Work, 0, r2, c2,do_Fcpos));
+               }
+               Row_tuples [row] = t2 ;
+               tp2 = (Tuple *) (Memory + t2) ;
+               if (t1)
+               {
+                   for (i = 0 ; i < len ; i++)
+                   {
+                       *tp2++ = *tp1++ ;
+                   }
+                   UMF_mem_free_tail_block (Numeric, t1) ;
+               }
+           }
+
+           /* place the new (e,f) tuple in the element list of the row */
+           Row_tlen [row]++ ;
+           *tp2 = tuple ;
+       }
+
+    }
+
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    DEBUG1 (("Done extending\nFINAL: element row pattern: len="ID"\n", fncols));
+    for (j = 0 ; j < fncols ; j++) DEBUG1 ((""ID"\n", Fcols [j])) ;
+    DEBUG1 (("FINAL: element col pattern:  len="ID"\n", fnrows)) ;
+    for (j = 0 ; j < fnrows ; j++) DEBUG1 ((""ID"\n", Frows [j])) ;
+    for (j = 0 ; j < fncols ; j++)
+    {
+       col = Fcols [j] ;
+       ASSERT (col >= 0 && col < n_col) ;
+       UMF_dump_rowcol (1, Numeric, Work, col, !Symbolic->fixQ) ;
+    }
+    for (j = 0 ; j < fnrows ; j++)
+    {
+       row = Frows [j] ;
+       ASSERT (row >= 0 && row < n_row) ;
+       UMF_dump_rowcol (0, Numeric, Work, row, TRUE) ;
+    }
+    if (n_row < 1000 && n_col < 1000)
+    {
+       UMF_dump_memory (Numeric) ;
+    }
+    DEBUG1 (("New element, after filling with stuff: "ID"\n", e)) ;
+    UMF_dump_element (Numeric, Work, e, TRUE) ;
+    if (nn < 1000)
+    {
+       DEBUG4 (("Matrix dump, after New element: "ID"\n", e)) ;
+       UMF_dump_matrix (Numeric, Work, TRUE) ;
+    }
+    DEBUG3 (("FRONTAL WRAPUP DONE\n")) ;
+#endif
+
+    return (TRUE) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_create_element.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_create_element.h
new file mode 100644 (file)
index 0000000..81df97f
--- /dev/null
@@ -0,0 +1,13 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_create_element
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    SymbolicType *Symbolic
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_dump.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_dump.c
new file mode 100644 (file)
index 0000000..9990c2c
--- /dev/null
@@ -0,0 +1,1220 @@
+/* ========================================================================== */
+/* === UMF_dump ============================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* These routines, and external variables, are used only when debugging. */
+/* If debugging is disabled (for normal operation) then this entire file */
+/* becomes empty */
+
+#include "umf_internal.h"
+
+#ifndef NDEBUG
+
+/* These global debugging variables and arrays do not exist if debugging */
+/* is disabled at compile time (which is the default). */
+GLOBAL Int UMF_debug = -999 ;
+GLOBAL Int UMF_allocfail = FALSE ;
+GLOBAL double UMF_gprob = -1.0 ;
+
+/* static debugging arrays used only in UMF_dump_rowcol */
+PRIVATE Int UMF_DBflag = 0 ;
+PRIVATE Int UMF_DBpacked [UMF_DBMAX+1] ;
+PRIVATE Int UMF_DBscatter [UMF_DBMAX+1] ;
+
+/* ========================================================================== */
+/* === UMF_DBinit =========================================================== */
+/* ========================================================================== */
+
+/* clear the debugging arrays */
+
+PRIVATE void UMF_DBinit
+(
+    void
+)
+{
+    Int i ;
+
+    /* Int_MAX is defined in umfpack.h */
+    if (UMF_DBflag < 1 || UMF_DBflag == Int_MAX)
+    {
+       /* clear the debugging arrays */
+       UMF_DBflag = 0 ;
+       for (i = 0 ; i <= UMF_DBMAX ; i++)
+       {
+           UMF_DBscatter [i] = 0 ;
+           UMF_DBpacked  [i] = 0 ;
+       }
+    }
+
+    UMF_DBflag++ ;
+
+    /* UMF_DBflag > UMF_DBscatter [0...UMF_DBmax] is now true */
+}
+
+/* ========================================================================== */
+/* === UMF_dump_dense ======================================================= */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_dense
+(
+    Entry *C,
+    Int dim,
+    Int m,
+    Int n
+)
+{
+
+    /* dump C [1..m,1..n], with column dimenstion dim */
+    Int i, j;
+
+    if (UMF_debug < 7) return ;
+    if (C == (Entry *) NULL)
+    {
+       DEBUG7 (("No dense matrix allocated\n")) ;
+       return ;
+    }
+    DEBUG8 ((" dimension= "ID" rows= "ID" cols= "ID"\n", dim, m, n)) ;
+
+    for (i = 0 ; i < m ; i++)
+    {
+       DEBUG9 ((ID": ", i)) ;
+       for (j = 0 ; j < n ; j++)
+       {
+           EDEBUG9 (C [i+j*dim]) ;
+           if (j % 6 == 5) DEBUG9 (("\n     ")) ;
+       }
+       DEBUG9 (("\n")) ;
+    }
+
+    for (i = 0 ; i < m ; i++)
+    {
+       for (j = 0 ; j < n ; j++)
+       {
+           if (IS_ZERO (C [i+j*dim]))
+           {
+               DEBUG8 ((".")) ;
+           }
+           else
+           {
+               DEBUG8 (("X")) ;
+           }
+       }
+       DEBUG8 (("\n")) ;
+    }
+}
+
+/* ========================================================================== */
+/* === UMF_dump_element ===================================================== */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_element
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    Int e,
+    Int clean
+)
+{
+
+    Int i, j, k, *Rows, *Cols, nrows, ncols, *E, row, col,
+       *Row_degree, *Col_degree ;
+    Entry *C ;
+    Element *ep ;
+    Unit *p ;
+
+    if (UMF_debug < 7) return ;
+
+    if (e == 0)
+    {
+       UMF_dump_current_front (Numeric, Work, FALSE) ;
+       return ;
+    }
+
+    DEBUG7 (("\n====================ELEMENT: "ID" ", e)) ;
+    if (!Numeric || !Work || !Numeric->Memory)
+    {
+       DEBUG7 ((" No Numeric, Work\n")) ;
+       return ;
+    }
+    DEBUG7 ((" nel: "ID" of "ID, e, Work->nel)) ;
+    E = Work->E ;
+    if (!E)
+    {
+       DEBUG7 ((" No elements\n")) ;
+       return ;
+    }
+    if (e < 0 || e > Work->nel)
+    {
+       DEBUG7 (("e out of range!\n")) ;
+       return ;
+    }
+    if (!E [e])
+    {
+       DEBUG7 ((" deallocated\n")) ;
+       return ;
+    }
+    DEBUG7 (("\n")) ;
+    Col_degree = Numeric->Cperm ;
+    Row_degree = Numeric->Rperm ;
+
+    p = Numeric->Memory + E [e] ;
+    DEBUG7 (("ep "ID"\n", (Int) (p-Numeric->Memory))) ;
+    GET_ELEMENT (ep, p, Cols, Rows, ncols, nrows, C) ;
+    DEBUG7 (("nrows "ID" nrowsleft "ID"\n", nrows, ep->nrowsleft)) ;
+    DEBUG7 (("ncols "ID" ncolsleft "ID"\n", ncols, ep->ncolsleft)) ;
+    DEBUG7 (("cdeg-cdeg0 "ID" rdeg-rdeg0 "ID" next "ID"\n",
+    ep->cdeg - Work->cdeg0, ep->rdeg - Work->rdeg0, ep->next)) ;
+
+    DEBUG8 (("rows: ")) ;
+    k = 0 ;
+    for (i = 0 ; i < ep->nrows ; i++)
+    {
+       row = Rows [i] ;
+       if (row >= 0)
+       {
+           DEBUG8 ((" "ID, row)) ;
+           ASSERT (row < Work->n_row) ;
+           if ((k++ % 10) == 9) DEBUG8 (("\n")) ;
+           ASSERT (IMPLIES (clean, NON_PIVOTAL_ROW (row))) ;
+       }
+    }
+
+    DEBUG8 (("\ncols: ")) ;
+    k = 0 ;
+    for (j = 0 ; j < ep->ncols ; j++)
+    {
+       col = Cols [j] ;
+       if (col >= 0)
+       {
+           DEBUG8 ((" "ID, col)) ;
+           ASSERT (col < Work->n_col) ;
+           if ((k++ % 10) == 9) DEBUG8 (("\n")) ;
+           ASSERT (IMPLIES (clean, NON_PIVOTAL_COL (col))) ;
+       }
+    }
+
+    DEBUG8 (("\nvalues:\n")) ;
+    if (UMF_debug >= 9)
+    {
+       for (i = 0 ; i < ep->nrows ; i++)
+       {
+           row = Rows [i] ;
+           if (row >= 0)
+           {
+               DEBUG9 ((ID": ", row)) ;
+               k = 0 ;
+               for (j = 0 ; j < ep->ncols ; j++)
+               {
+                   col = Cols [j] ;
+                   if (col >= 0)
+                   {
+                       EDEBUG9 (C [i+j*ep->nrows]) ;
+                       if (k++ % 6 == 5) DEBUG9 (("\n     ")) ;
+                   }
+               }
+               DEBUG9 (("\n")) ;
+           }
+       }
+    }
+
+    DEBUG7 (("====================\n")) ;
+}
+
+
+/* ========================================================================== */
+/* === UMF_dump_rowcol ====================================================== */
+/* ========================================================================== */
+
+/* dump a row or a column, from one or more memory spaces */
+/* return exact degree */
+
+GLOBAL void UMF_dump_rowcol
+(
+    Int dumpwhich,             /* 0 for row, 1 for column */
+    NumericType *Numeric,
+    WorkType *Work,
+    Int dumpindex,             /* row or column index to dump */
+    Int check_degree   /* true if degree is to be checked */
+)
+{
+    Int f, nrows, j, jj, len, e, deg, index, n_row, n_col, *Cols, *Rows, nn,
+       dumpdeg, ncols, preve, *E, tpi, *Pattern, approx_deg, not_in_use ;
+    Tuple *tp, *tend ;
+    Element *ep ;
+    Int *Row_tuples, *Row_degree, *Row_tlen ;
+    Int *Col_tuples, *Col_degree, *Col_tlen ;
+    Entry value, *C ;
+    Unit *p ;
+    Int is_there ;
+
+    /* clear the debugging arrays */
+    UMF_DBinit () ;
+
+    if (dumpwhich == 0)
+    {
+       DEBUG7 (("\n====================ROW: "ID, dumpindex)) ;
+    }
+    else
+    {
+       DEBUG7 (("\n====================COL: "ID, dumpindex)) ;
+    }
+
+    if (dumpindex == EMPTY)
+    {
+       DEBUG7 ((" (EMPTY)\n")) ;
+       return ;
+    }
+
+    deg = 0 ;
+    approx_deg = 0 ;
+
+    if (!Numeric || !Work)
+    {
+       DEBUG7 ((" No Numeric, Work\n")) ;
+       return ;
+    }
+
+    n_row = Work->n_row ;
+    n_col = Work->n_col ;
+    nn = MAX (n_row, n_col) ;
+    E = Work->E ;
+
+    Col_degree = Numeric->Cperm ;
+    Row_degree = Numeric->Rperm ;
+
+    Row_tuples = Numeric->Uip ;
+    Row_tlen   = Numeric->Uilen ;
+    Col_tuples = Numeric->Lip ;
+    Col_tlen   = Numeric->Lilen ;
+
+       if (!E
+       || !Row_tuples || !Row_degree || !Row_tlen
+       || !Col_tuples || !Col_degree || !Col_tlen)
+       {
+           DEBUG7 ((" No E, Rows, Cols\n")) ;
+           return ;
+       }
+
+       if (dumpwhich == 0)
+       {
+           /* dump a row */
+           ASSERT (dumpindex >= 0 && dumpindex < n_row) ;
+           if (!NON_PIVOTAL_ROW (dumpindex))
+           {
+               DEBUG7 ((" Pivotal\n")) ;
+               return ;
+           }
+           len = Row_tlen [dumpindex] ;
+           dumpdeg = Row_degree [dumpindex] ;
+           tpi = Row_tuples [dumpindex] ;
+       }
+       else
+       {
+           /* dump a column */
+           ASSERT (dumpindex >= 0 && dumpindex < n_col) ;
+           if (!NON_PIVOTAL_COL (dumpindex))
+           {
+               DEBUG7 ((" Pivotal\n")) ;
+               return ;
+           }
+           len = Col_tlen [dumpindex] ;
+           dumpdeg = Col_degree [dumpindex] ;
+           tpi = Col_tuples [dumpindex] ;
+       }
+
+       p = Numeric->Memory + tpi ;
+       tp = (Tuple *) p ;
+       if (!tpi)
+       {
+           DEBUG7 ((" Nonpivotal, No tuple list tuples "ID" tlen "ID"\n",
+               tpi, len)) ;
+           return ;
+       }
+       ASSERT (p >= Numeric->Memory + Numeric->itail) ;
+       ASSERT (p <  Numeric->Memory + Numeric->size) ;
+
+       DEBUG7 ((" degree: "ID" len: "ID"\n", dumpdeg, len)) ;
+       not_in_use = (p-1)->header.size - UNITS (Tuple, len) ;
+       DEBUG7 ((" Tuple list: p+1: "ID" size: "ID" units, "ID" not in use\n",
+               (Int) (p-Numeric->Memory), (p-1)->header.size, not_in_use)) ;
+       ASSERT (not_in_use >= 0) ;
+       tend = tp + len ;
+       preve = 0 ;
+       for ( ; tp < tend ; tp++)
+       {
+           /* row/col of element e, offset is f: */
+           /* DEBUG8 (("    (tp="ID")\n", tp)) ; */
+           e = tp->e ;
+           f = tp->f ;
+           DEBUG8 (("    (e="ID", f="ID")\n", e, f)) ;
+           ASSERT (e > 0 && e <= Work->nel) ;
+           /* dump the pattern and values */
+           if (E [e])
+           {
+               p = Numeric->Memory + E [e] ;
+               GET_ELEMENT (ep, p, Cols, Rows, ncols, nrows, C) ;
+               if (dumpwhich == 0)
+               {
+                   Pattern = Cols ;
+                   jj = ep->ncols ;
+                   is_there = Rows [f] >= 0 ;
+                   if (is_there) approx_deg += ep->ncolsleft ;
+               }
+               else
+               {
+                   Pattern = Rows ;
+                   jj = ep->nrows ;
+                   is_there = Cols [f] >= 0 ;
+                   if (is_there) approx_deg += ep->nrowsleft ;
+               }
+               if (!is_there)
+               {
+                       DEBUG8 (("\t\tnot present\n")) ;
+               }
+               else
+               {
+                   for (j = 0 ; j < jj ; j++)
+                   {
+                       index = Pattern [j] ;
+                       value =
+                           C [ (dumpwhich == 0) ? (f+nrows*j) : (j+nrows*f) ] ;
+                       if (index >= 0)
+                       {
+                           DEBUG8 (("\t\t"ID":", index)) ;
+                           EDEBUG8 (value) ;
+                           DEBUG8 (("\n")) ;
+                           if (dumpwhich == 0)
+                           {
+                               /* col must be in the range 0..n_col-1 */
+                               ASSERT (index < n_col) ;
+                           }
+                           else
+                           {
+                               /* row must be in the range 0..n_row-1 */
+                               ASSERT (index < n_row) ;
+                           }
+
+                           if (nn <= UMF_DBMAX)
+                           {
+                               if (UMF_DBscatter [index] != UMF_DBflag)
+                               {
+                                   UMF_DBpacked [deg++] = index ;
+                                   UMF_DBscatter [index] = UMF_DBflag ;
+                               }
+                           }
+                       }
+                   }
+               }
+               /* the (e,f) tuples should be in order of their creation */
+               /* this means that garbage collection will not jumble them */
+               ASSERT (preve < e) ;
+               preve = e ;
+           }
+           else
+           {
+               DEBUG8 (("\t\tdeallocated\n")) ;
+           }
+       }
+
+    if (nn <= UMF_DBMAX)
+    {
+       if (deg > 0)
+       {
+           DEBUG7 ((" Assembled, actual deg: "ID" : ", deg)) ;
+           for (j = 0 ; j < deg ; j++)
+           {
+               index = UMF_DBpacked [j] ;
+               DEBUG8 ((ID" ", index)) ;
+               if (j % 20 == 19) DEBUG8 (("\n ")) ;
+               ASSERT (UMF_DBscatter [index] == UMF_DBflag) ;
+           }
+           DEBUG7 (("\n")) ;
+       }
+    }
+
+    /* Col_degree is not maintained when fixQ is true */
+    if (check_degree)
+    {
+       DEBUG8 (("  approx_deg "ID"  dumpdeg "ID"\n", approx_deg, dumpdeg)) ;
+       ASSERT (approx_deg == dumpdeg) ;
+    }
+
+    DEBUG7 (("====================\n")) ;
+
+    /* deg is now the exact degree */
+    /* if nn <= UMF_DBMAX, then UMF_DBscatter [i] == UMF_DBflag for every i */
+    /* in the row or col, and != UMF_DBflag if not */
+
+    return ;
+}
+
+
+/* ========================================================================== */
+/* === UMF_dump_matrix ====================================================== */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_matrix
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    Int check_degree
+)
+{
+
+    Int e, row, col, intfrag, frag, n_row, n_col, *E, fullsize, actualsize ;
+    Element *ep ;
+    Unit *p ;
+
+    DEBUG6 (("=================================================== MATRIX:\n")) ;
+    if (!Numeric || !Work)
+    {
+       DEBUG6 (("No Numeric or Work allocated\n")) ;
+       return ;
+    }
+    if (!Numeric->Memory)
+    {
+       DEBUG6 (("No Numeric->Memory\n")) ;
+       return ;
+    }
+
+       n_row = Work->n_row ;
+       n_col = Work->n_col ;
+       DEBUG6 (("n_row "ID" n_col "ID" nz "ID"\n", n_row, n_col, Work->nz)) ;
+       DEBUG6 (("============================ ELEMENTS: "ID" \n", Work->nel)) ;
+       intfrag = 0 ;
+       E = Work->E ;
+       if (!E)
+       {
+           DEBUG6 (("No elements allocated\n")) ;
+       }
+       else
+       {
+           for (e = 0 ; e <= Work->nel ; e++)
+           {
+               UMF_dump_element (Numeric, Work, e, FALSE) ;
+               if (e > 0 && E [e])
+               {
+                   p = Numeric->Memory + E [e] ;
+                   ep = (Element *) p ;
+                   ASSERT (ep->nrowsleft > 0 || ep->ncolsleft > 0) ;
+                   fullsize = GET_BLOCK_SIZE (p) ;
+                   actualsize = GET_ELEMENT_SIZE (ep->nrowsleft,ep->ncolsleft);
+                   frag =  fullsize - actualsize ;
+                   intfrag += frag ;
+                   DEBUG7 (("dump el: "ID", full "ID" actual "ID" frag: "ID
+                       " intfrag: "ID"\n", e, fullsize, actualsize, frag,
+                       intfrag)) ;
+               }
+           }
+       }
+
+       DEBUG6 (("CURRENT INTERNAL FRAG in elements: "ID" \n", intfrag)) ;
+
+
+
+    DEBUG6 (("======================================== ROWS: "ID"\n", n_row)) ;
+    UMF_debug -= 2 ;
+    for (row = 0 ; row < n_row ; row++)
+    {
+       UMF_dump_rowcol (0, Numeric, Work, row, check_degree) ;
+    }
+    UMF_debug += 2 ;
+    DEBUG6 (("======================================== COLS: "ID"\n", n_col)) ;
+    UMF_debug -= 2 ;
+    for (col = 0 ; col < n_col ; col++)
+    {
+       UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ;
+    }
+    UMF_debug += 2 ;
+    DEBUG6 (("============================================= END OF MATRIX:\n"));
+}
+
+
+/* ========================================================================== */
+/* === UMF_dump_current_front =============================================== */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_current_front
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    Int check
+)
+{
+
+    Entry *Flublock, *Flblock, *Fublock, *Fcblock ;
+    Int fnrows_max, fncols_max, fnrows, fncols, fnpiv, *Frows, *Fcols,
+       i, j, *Fcpos, *Frpos, fnr_curr, fnc_curr, *E ;
+    if (!Work) return ;
+    DEBUG7 (("\n\n========CURRENT FRONTAL MATRIX:\n")) ;
+
+    Flublock = Work->Flublock ;
+    Flblock = Work->Flblock ;
+    Fublock = Work->Fublock ;
+    Fcblock = Work->Fcblock ;
+
+    Frows = Work->Frows ;
+    Fcols = Work->Fcols ;
+    Frpos = Work->Frpos ;
+    Fcpos = Work->Fcpos ;
+    fnrows_max = Work->fnrows_max ;
+    fncols_max = Work->fncols_max ;
+    fnr_curr = Work->fnr_curr ;
+    fnc_curr = Work->fnc_curr ;
+    fnrows = Work->fnrows ;
+    fncols = Work->fncols ;
+    fnpiv = Work->fnpiv ;
+    E = Work->E ;
+
+    DEBUG6 (("=== fnpiv= "ID"\n", fnpiv)) ;
+    DEBUG6 (("fnrows_max      fncols_max "ID" "ID"\n",fnrows_max, fncols_max)) ;
+    DEBUG6 (("fnr_curr        fnc_curr   "ID" "ID"\n",fnr_curr,   fnc_curr)) ;
+    DEBUG6 (("fnrows          fncols     "ID" "ID"\n",fnrows,     fncols)) ;
+    ASSERT ((fnr_curr % 2 == 1) || fnr_curr == 0) ;
+    DEBUG6 (("Pivot row pattern:\n")) ;
+    for (j = 0 ; j < fncols ; j++)
+    {
+       DEBUG7 ((ID" "ID" "ID" %d\n", j, Fcols [j], Fcpos [Fcols [j]],
+           j < fncols)) ;
+       if (check)
+       {
+           ASSERT (Fcols [j] >= 0 && Fcols [j] < Work->n_col) ;
+           ASSERT (Fcpos [Fcols [j]] == j * fnr_curr) ;
+       }
+    }
+    DEBUG6 (("Pivot col pattern:\n")) ;
+    for (i = 0 ; i < fnrows ; i++)
+    {
+       DEBUG7 ((ID" "ID" "ID" %d\n", i, Frows [i], Frpos [Frows [i]],
+           i < fnrows)) ;
+       if (check)
+       {
+           ASSERT (Frows [i] >= 0 && Frows [i] < Work->n_row) ;
+           ASSERT (Frpos [Frows [i]] == i) ;
+       }
+    }
+    if (UMF_debug < 7) return ;
+
+    if (!E [0])
+    {
+       DEBUG6 (("current front not allocated\n")) ;
+       ASSERT (!Work->Flublock) ;
+       return ;
+    }
+
+    ASSERT (Work->Flublock == (Entry *) (Numeric->Memory + E [0])) ;
+    DEBUG7 (("C  block: ")) ;
+    UMF_dump_dense (Fcblock,  fnr_curr, fnrows, fncols) ;
+    DEBUG7 (("L  block: ")) ;
+    UMF_dump_dense (Flblock,  fnr_curr, fnrows, fnpiv) ;
+    DEBUG7 (("U' block: ")) ;
+    UMF_dump_dense (Fublock,  fnc_curr, fncols, fnpiv) ;
+    DEBUG7 (("LU block: ")) ;
+    UMF_dump_dense (Flublock, Work->nb, fnpiv, fnpiv) ;
+    if (fnpiv > 0)
+    {
+       DEBUG7 (("Pivot entry: ")) ;
+       EDEBUG7 (Flublock [(fnpiv-1)+(fnpiv-1)*Work->nb]) ;
+       DEBUG7 (("\n")) ;
+    }
+}
+
+/* ========================================================================== */
+/* === UMF_dump_lu ========================================================== */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_lu
+(
+    NumericType *Numeric
+)
+{
+    Int i, n_row, n_col, *Cperm, *Rperm ;
+
+    DEBUG6 (("=============================================== LU factors:\n")) ;
+    if (!Numeric)
+    {
+       DEBUG6 (("No LU factors allocated\n")) ;
+       return ;
+    }
+    n_row = Numeric->n_row ;
+    n_col = Numeric->n_col ;
+    DEBUG6 (("n_row: "ID" n_col: "ID"\n", n_row, n_col)) ;
+    DEBUG6 (("nLentries: "ID" nUentries: "ID"\n",
+       Numeric->nLentries, Numeric->nUentries)) ;
+
+    if (Numeric->Cperm)
+    {
+       Cperm = Numeric->Cperm ;
+       DEBUG7 (("Column permutations: (new: old)\n")) ;
+       for (i = 0 ; i < n_col ; i++)
+       {
+           if (Cperm [i] != EMPTY)
+           {
+               DEBUG7 ((ID": "ID"\n", i, Cperm [i])) ;
+           }
+       }
+    }
+    else
+    {
+       DEBUG7 (("No Numeric->Cperm allocatated\n")) ;
+    }
+
+    if (Numeric->Rperm)
+    {
+       Rperm = Numeric->Rperm ;
+       DEBUG7 (("row permutations: (new: old)\n")) ;
+       for (i = 0 ; i < n_row ; i++)
+       {
+           if (Rperm [i] != EMPTY)
+           {
+               DEBUG7 ((ID": "ID"\n", i, Rperm [i])) ;
+           }
+       }
+    }
+    else
+    {
+       DEBUG7 (("No Numeric->Rperm allocatated\n")) ;
+    }
+
+    DEBUG6 (("========================================= END OF LU factors:\n"));
+}
+
+
+/* ========================================================================== */
+/* === UMF_dump_memory ====================================================== */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_memory
+(
+    NumericType *Numeric
+)
+{
+
+    Unit *p ;
+    Int prevsize, s ;
+    Int found ;
+
+    if (!Numeric)
+    {
+       DEBUG6 (("No memory space S allocated\n")) ;
+       return ;
+    }
+
+    DEBUG6 (("\n ============================================== MEMORY:\n")) ;
+    if (!Numeric || !Numeric->Memory)
+    {
+       DEBUG6 (("No memory space Numeric allocated\n")) ;
+       return ;
+    }
+
+    DEBUG6 (("S: "ID"\n", (Int) Numeric)) ;
+    DEBUG6 (("S->ihead           : "ID"\n", Numeric->ihead)) ;
+    DEBUG6 (("S->itail           : "ID"\n", Numeric->itail)) ;
+    DEBUG6 (("S->size            : "ID"\n", Numeric->size)) ;
+    DEBUG6 (("S->ngarbage        : "ID"\n", Numeric->ngarbage)) ;
+    DEBUG6 (("S->nrealloc        : "ID"\n", Numeric->nrealloc)) ;
+    DEBUG6 (("   in use at head           : "ID"\n", Numeric->ihead)) ;
+    DEBUG6 (("   free space               : "ID"\n",
+       Numeric->itail - Numeric->ihead)) ;
+    DEBUG6 (("   blocks in use at tail    : "ID"\n",
+       Numeric->size - Numeric->itail)) ;
+    DEBUG6 (("   total in use             : "ID"\n",
+       Numeric->size - (Numeric->itail - Numeric->ihead))) ;
+
+    prevsize = 0 ;
+    found = FALSE ;
+
+    ASSERT (0 <= Numeric->ihead) ;
+    ASSERT (Numeric->ihead <= Numeric->itail) ;
+    ASSERT (Numeric->itail <= Numeric->size) ;
+
+    p = Numeric->Memory + Numeric->itail ;
+
+    while (p < Numeric->Memory + Numeric->size)
+    {
+       DEBUG8 (("p: "ID" p+1: "ID" prevsize: "ID" size: "ID,
+           (Int) (p-Numeric->Memory), (Int) (p+1-Numeric->Memory),
+           p->header.prevsize, p->header.size)) ;
+       if (p->header.size < 0)
+       {
+           DEBUG8 ((" free")) ;
+       }
+
+       if (p == Numeric->Memory + Numeric->itail)
+       {
+           ASSERT (p->header.prevsize == 0) ;
+       }
+       else
+       {
+           ASSERT (p->header.prevsize > 0) ;
+       }
+
+       ASSERT (p->header.size != 0) ;
+       s = prevsize >= 0 ? prevsize : -prevsize ;
+       ASSERT (p->header.prevsize == s) ;
+       /* no adjacent free blocks */
+       ASSERT (p->header.size > 0 || prevsize > 0) ;
+       if (Numeric->ibig != EMPTY)
+       {
+           if (p == Numeric->Memory + Numeric->ibig)
+           {
+               ASSERT (p->header.size < 0) ;
+               DEBUG8 ((" <===== Numeric->ibig")) ;
+               found = TRUE ;
+           }
+       }
+       s = p->header.size ;
+       prevsize = s ;
+       s = s >= 0 ? s : -s ;
+       p = p + 1 + s ;
+       DEBUG8 (("\n")) ;
+    }
+
+    ASSERT (p == Numeric->Memory + Numeric->size) ;
+    ASSERT (IMPLIES (Numeric->ibig != EMPTY, found)) ;
+    DEBUG6 (("============================================= END OF MEMORY:\n"));
+
+}
+
+
+/* ========================================================================== */
+/* === UMF_dump_packed_memory =============================================== */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_packed_memory
+(
+    NumericType *Numeric,
+    WorkType *Work
+)
+{
+    Unit *p, *p3 ;
+    Int prevsize, col, row, *Rows, *Cols, ncols, nrows, k, esize,
+       *Row_tuples, *Row_degree, *Col_tuples, *Col_degree ;
+    Entry *C ;
+    Element *ep ;
+
+    Col_degree = Numeric->Cperm ;      /* for NON_PIVOTAL_COL macro */
+    Row_degree = Numeric->Rperm ;      /* for NON_PIVOTAL_ROW macro */
+    Row_tuples = Numeric->Uip ;
+    Col_tuples = Numeric->Lip ;
+
+    DEBUG6 (("============================================ PACKED MEMORY:\n")) ;
+    if (!Numeric || !Numeric->Memory)
+    {
+       DEBUG6 (("No memory space S allocated\n")) ;
+       return ;
+    }
+    DEBUG6 (("S: "ID"\n", (Int) Numeric)) ;
+    DEBUG6 (("S->ihead           : "ID"\n", Numeric->ihead)) ;
+    DEBUG6 (("S->itail           : "ID"\n", Numeric->itail)) ;
+    DEBUG6 (("S->size            : "ID"\n", Numeric->size)) ;
+    DEBUG6 (("S->ngarbage        : "ID"\n", Numeric->ngarbage)) ;
+    DEBUG6 (("S->nrealloc        : "ID"\n", Numeric->nrealloc)) ;
+    DEBUG6 (("   in use at head           : "ID"\n", Numeric->ihead)) ;
+    DEBUG6 (("   free space               : "ID"\n",
+       Numeric->itail - Numeric->ihead)) ;
+    DEBUG6 (("   blocks in use at tail    : "ID"\n",
+       Numeric->size - Numeric->itail)) ;
+    DEBUG6 (("   total in use             : "ID"\n",
+       Numeric->size - (Numeric->itail - Numeric->ihead))) ;
+
+    ASSERT (0 <= Numeric->ihead) ;
+    ASSERT (Numeric->ihead <= Numeric->itail) ;
+    ASSERT (Numeric->itail <= Numeric->size) ;
+
+    for (row = 0 ; row < Work->n_row ; row++)
+    {
+       ASSERT (IMPLIES (NON_PIVOTAL_ROW (row), !Row_tuples [row])) ;
+    }
+    for (col = 0 ; col < Work->n_col ; col++)
+    {
+       ASSERT (IMPLIES (NON_PIVOTAL_COL (col), !Col_tuples [col])) ;
+    }
+
+    prevsize = 0 ;
+    p = Numeric->Memory + Numeric->itail ;
+    while (p < Numeric->Memory + Numeric->size)
+    {
+       DEBUG9 (("====================\n")) ;
+       DEBUG7 (("p: "ID" p+1: "ID" prevsize: "ID" size: "ID"\n",
+           (Int) (p-Numeric->Memory), (Int) (p+1-Numeric->Memory),
+           p->header.prevsize, p->header.size)) ;
+       ASSERT (p->header.size > 0) ;
+
+       if (p == Numeric->Memory + Numeric->itail)
+       {
+           ASSERT (p->header.prevsize == 0) ;
+       }
+       else
+       {
+           ASSERT (p->header.prevsize > 0) ;
+       }
+
+       ASSERT (p->header.prevsize == prevsize) ;
+       prevsize = p->header.size ;
+
+       if (p != Numeric->Memory + Numeric->size - 2)
+       {
+
+           p3 = p + 1 ;
+           if (p3 == Numeric->Memory + Work->E [0])
+           {
+               /* this is the current frontal matrix */
+               UMF_dump_current_front (Numeric, Work, FALSE) ;
+           }
+           else
+           {
+
+               /* this is a packed element */
+               GET_ELEMENT (ep, p3, Cols, Rows, ncols, nrows, C) ;
+               DEBUG9 (("ep "ID"\n nrows "ID" ncols "ID"\n",
+                   (Int) ((p+1)-Numeric->Memory), ep->nrows, ep->ncols)) ;
+               DEBUG9 (("rows:")) ;
+               for (k = 0 ; k < ep->nrows; k++)
+               {
+                   row = Rows [k] ;
+                   DEBUG9 ((" "ID, row)) ;
+                   ASSERT (row >= 0 && row <= Work->n_row) ;
+                   if ((k % 10) == 9) DEBUG9 (("\n")) ;
+               }
+               DEBUG9 (("\ncols:")) ;
+               for (k = 0 ; k < ep->ncols; k++)
+               {
+                   col = Cols [k] ;
+                   DEBUG9 ((" "ID, col)) ;
+                   ASSERT (col >= 0 && col <= Work->n_col) ;
+                   if ((k % 10) == 9) DEBUG9 (("\n")) ;
+               }
+               DEBUG9 (("\nvalues: ")) ;
+               if (UMF_debug >= 9)
+               {
+                   UMF_dump_dense (C, ep->nrows, ep->nrows, ep->ncols) ;
+               }
+               esize = GET_ELEMENT_SIZE (ep->nrows, ep->ncols) ;
+               DEBUG9 (("esize: "ID"\n", esize)) ;
+               ASSERT (esize <= p->header.size) ;
+           }
+
+       }
+       else
+       {
+           /* this is the final marker block */
+           ASSERT (p->header.size == 1) ;
+       }
+       p = p + 1 + p->header.size ;
+    }
+
+    ASSERT (Numeric->ibig == EMPTY) ;
+    ASSERT (p == Numeric->Memory + Numeric->size) ;
+    DEBUG6 (("======================================END OF PACKED MEMORY:\n")) ;
+
+}
+
+/* ========================================================================== */
+/* === UMF_dump_col_matrix ================================================== */
+/* ========================================================================== */
+
+/* This code is the same for real or complex matrices. */
+
+GLOBAL void UMF_dump_col_matrix
+(
+    const double Ax [ ],       /* Ax [0..nz-1]: real values, in column order */
+#ifdef COMPLEX
+    const double Az [ ],       /* Az [0..nz-1]: imag values, in column order */
+#endif
+    const Int Ai [ ],          /* Ai [0..nz-1]: row indices, in column order */
+    const Int Ap [ ],          /* Ap [0..n_col]: column pointers */
+    Int n_row,                 /* number of rows of A */
+    Int n_col,                 /* number of columns of A */
+    Int nz                     /* number of entries */
+)
+{
+    Int col, p, p1, p2, row ;
+    if (!Ai || !Ap) return ;
+    DEBUG6 (("============================================ COLUMN FORM:\n")) ;
+
+
+    ASSERT (n_col >= 0) ;
+    nz = Ap [n_col] ;
+    DEBUG2 (("UMF_dump_col:  nz "ID"\n", nz)) ;
+    DEBUG2 (("n_row "ID"  \n", n_row)) ;
+    DEBUG2 (("n_col "ID"  \n", n_col)) ;
+
+    DEBUG6 ((" n_row = "ID", n_col ="ID" nz = "ID" Ap [0] "ID", Ap [n] "ID"\n",
+       n_row, n_col, nz, Ap [0], Ap [n_col])) ;
+    ASSERT (Ap [0] == 0) ;
+    ASSERT (Ap [n_col] == nz) ;
+    for (col = 0 ; col < n_col ; col++)
+    {
+       p1 = Ap [col] ;
+       p2 = Ap [col+1] ;
+       DEBUG6 (("col: "ID", length "ID"\n", col, p2 - p1)) ;
+       ASSERT (p2 >= p1) ;
+       for (p = p1 ; p < p2 ; p++)
+       {
+           row = Ai [p] ;
+           ASSERT (row >= 0 && row < n_row) ;
+           DEBUG6 (("\t"ID" ", row)) ;
+           if (Ax != (double *) NULL)
+           {
+#ifdef COMPLEX
+               if (Az != (double *) NULL)
+               {
+                   DEBUG6 ((" (%e+%ei) ", Ax [p], Az [p])) ;
+               }
+               else
+               {
+                   DEBUG6 ((" %e", Ax [p])) ;
+               }
+#else
+               DEBUG6 ((" %e", Ax [p])) ;
+#endif
+           }
+           DEBUG6 (("\n")) ;
+       }
+    }
+    DEBUG6 (("========================================== COLUMN FORM done\n")) ;
+}
+
+
+/* ========================================================================== */
+/* === UMF_dump_chain ======================================================= */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_chain
+(
+    Int frontid,
+    Int Front_parent [ ],
+    Int Front_npivcol [ ],
+    Int Front_nrows [ ],
+    Int Front_ncols [ ],
+    Int nfr
+)
+{
+    Int i, len = 0 ;
+
+    /* print a list of contiguous parents */
+    i = frontid ;
+    ASSERT (Front_parent [i] == EMPTY ||
+       (Front_parent [i] > i && Front_parent [i] < nfr)) ;
+
+    len++ ;
+    DEBUG3 (("Chain:\n "ID" ["ID","ID"]("ID"-by-"ID")\n", i,
+               Front_npivcol [i],
+               MIN (Front_npivcol [i], Front_nrows [i]),
+               Front_nrows [i],
+               Front_ncols [i])) ;
+
+    for (i = frontid ; i < nfr ; i++)
+    {
+       ASSERT (Front_parent [i] == EMPTY ||
+       (Front_parent [i] > i && Front_parent [i] < nfr)) ;
+       if (Front_parent [i] == i+1)
+       {
+           len++ ;
+           DEBUG3 (("\t"ID" ["ID","ID"]("ID"-by-"ID")\n", i+1,
+               Front_npivcol [i+1],
+               MIN (Front_npivcol [i+1], Front_nrows [i+1]),
+               Front_nrows [i+1],
+               Front_ncols [i+1])) ;
+       }
+       else
+       {
+           DEBUG2 (("Length of chain: "ID"\n", len)) ;
+           return ;
+       }
+    }
+}
+
+
+/* ========================================================================== */
+/* === UMF_dump_start ======================================================= */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_start
+(
+    void
+)
+{
+    FILE *ff ;
+
+    /* get the debug print level from the "debug.umf" file, if it exists */
+    UMF_debug = -999 ;
+    ff = fopen ("debug.umf", "r") ;
+    if (ff)
+    {
+       (void) fscanf (ff, ID, &UMF_debug) ;
+       (void) fclose (ff) ;
+    }
+
+    DEBUG0 (("umfpack: debug version (SLOW!) ")) ;
+
+    DEBUG0 ((" BLAS: ")) ;
+
+#if defined (USE_NO_BLAS)
+    DEBUG0 (("none.")) ;
+#elif defined (USE_C_BLAS)
+    DEBUG0 (("C-BLAS.")) ;
+#elif defined (USE_MATLAB_BLAS)
+    DEBUG0 (("built-in MATLAB BLAS.")) ;
+#elif defined (USE_SUNPERF_BLAS)
+    DEBUG0 (("Sun Performance Library BLAS.")) ;
+#elif defined (USE_SCSL_BLAS)
+    DEBUG0 (("SGI SCSL BLAS.")) ;
+#elif defined (USE_FORTRAN_BLAS)
+    DEBUG0 (("Fortran BLAS.")) ;
+#endif
+
+    DEBUG0 ((" MATLAB: ")) ;
+#ifdef MATLAB_MEX_FILE
+    DEBUG0 (("mexFunction.\n")) ;
+#else
+#ifdef MATHWORKS
+    DEBUG0 (("yes (uses MathWorks internal ut* routines).\n")) ;
+#else
+    DEBUG0 (("no.\n")) ;
+#endif
+#endif
+
+    UMF_gprob = -1.0 ;
+    ff = fopen ("gprob.umf", "r") ;
+    if (ff)
+    {
+       (void) fscanf (ff, "%lg", &UMF_gprob) ;
+       (void) fclose (ff) ;
+       srand (1) ;     /* restart the random number generator */
+    }
+
+    if (UMF_gprob > 1.0) UMF_gprob = 1.0 ;
+    DEBUG1 (("factor: UMF_gprob: %e UMF_debug "ID"\n", UMF_gprob, UMF_debug)) ;
+
+    DEBUG2 (("sizeof: (bytes / int / Units) \n")) ;
+    DEBUG2 (("sizeof (Int)           %u %u %u\n",
+    sizeof (Int), sizeof (Int) / sizeof (int), UNITS (Int, 1) )) ;
+    DEBUG2 (("sizeof (int)           %u %u %u\n",
+    sizeof (int), sizeof (int) / sizeof (int), UNITS (int, 1) )) ;
+    DEBUG2 (("sizeof (size_t)        %u %u %u\n",
+    sizeof (size_t), sizeof (size_t) / sizeof (size_t), UNITS (size_t, 1) )) ;
+    DEBUG2 (("sizeof (long)          %u %u %u\n",
+    sizeof (long), sizeof (long) / sizeof (long), UNITS (long, 1) )) ;
+    DEBUG2 (("sizeof (double)        %u %u %u\n",
+    sizeof (double), sizeof (double) / sizeof (int), UNITS (double, 1) )) ;
+    DEBUG2 (("sizeof (Unit)          %u %u %u\n",
+    sizeof (Unit), sizeof (Unit) / sizeof (int), UNITS (Unit, 1) )) ;
+    DEBUG2 (("sizeof (Entry)         %u %u %u\n",
+    sizeof (Entry), sizeof (Entry) / sizeof (int), UNITS (Entry, 1) )) ;
+    DEBUG2 (("sizeof (Tuple)         %u %u %u\n",
+    sizeof (Tuple), sizeof (Tuple) / sizeof (int), UNITS (Tuple, 1) )) ;
+    DEBUG2 (("sizeof (Tuple *)       %u %u %u\n",
+    sizeof (Tuple *), sizeof (Tuple *) / sizeof (int), UNITS (Tuple *, 1) )) ;
+    DEBUG2 (("sizeof (Element)       %u %u %u\n",
+    sizeof (Element), sizeof (Element) / sizeof (int), UNITS (Element, 1) )) ;
+    DEBUG2 (("sizeof (Element *)     %u %u %u\n",
+    sizeof (Element *), sizeof (Element *) / sizeof (int),
+    UNITS (Element *, 1) )) ;
+    DEBUG2 (("sizeof (WorkType)      %u %u %u\n",
+    sizeof (WorkType), sizeof (WorkType) / sizeof (int),
+    UNITS (WorkType, 1) )) ;
+    DEBUG2 (("sizeof (NumericType)   %u %u %u\n",
+    sizeof (NumericType), sizeof (NumericType) / sizeof (int),
+    UNITS (NumericType, 1) )) ;
+    DEBUG2 (("sizeof (SymbolicType)  %u %u %u\n",
+    sizeof (SymbolicType), sizeof (SymbolicType) / sizeof (int),
+    UNITS (SymbolicType, 1) )) ;
+
+}
+
+
+/* ========================================================================== */
+/* === UMF_dump_rowmerge ==================================================== */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_rowmerge
+(
+    NumericType *Numeric,
+    SymbolicType *Symbolic,
+    WorkType *Work
+)
+{
+    Int *Front_leftmostdesc, *Front_1strow, *Front_new1strow, row1, row2,
+       fleftmost, nfr, n_row, *Row_degree, i, frontid, row ;
+
+    nfr = Symbolic->nfr ;
+    DEBUG3 (("\n================== Row merge sets: nfr "ID"\n", nfr)) ;
+    Front_leftmostdesc = Symbolic->Front_leftmostdesc ;
+    Front_1strow = Symbolic->Front_1strow ;
+    Front_new1strow = Work->Front_new1strow ;
+    n_row = Symbolic->n_row ;
+    Row_degree = Numeric->Rperm ;
+    frontid = Work->frontid ;
+
+    for (i = frontid ; i <= nfr ; i++)
+    {
+       DEBUG3 (("----------------------\n")) ;
+       if (i == nfr) DEBUG3 (("Dummy: ")) ;
+       DEBUG3 (("Front "ID" 1strow "ID" new1strow "ID" leftmostdesc "ID,
+           i, Front_1strow [i], Front_new1strow [i], Front_leftmostdesc [i])) ;
+       DEBUG3 ((" parent "ID" pivcol "ID"\n", Symbolic->Front_parent [i],
+           Symbolic->Front_npivcol [i])) ;
+
+       if (i == nfr)
+       {
+           fleftmost = -1 ;
+           row1 = Front_new1strow [i] ;
+           row2 = n_row-1 ;
+       }
+       else
+       {
+           fleftmost = Front_leftmostdesc [i] ;
+           row1 = Front_new1strow [fleftmost] ;
+           row2 = Front_1strow [i+1] - 1 ;
+       }
+       DEBUG3 (("Leftmost: "ID"  Rows ["ID" to "ID"], search ["ID" to "ID"]\n",
+           fleftmost, Front_1strow [i], row2, row1, row2)) ;
+
+       for (row = row1 ; row <= row2 ; row++)
+       {
+           ASSERT (row >= 0 && row < n_row) ;
+           DEBUG3 (("   Row "ID" live: %d\n", row, NON_PIVOTAL_ROW (row))) ;
+       }
+    }
+}
+
+/* ========================================================================== */
+/* === UMF_dump_diagonal_map ================================================ */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_diagonal_map
+(
+    Int Diagonal_map [ ],
+    Int Diagonal_imap [ ],
+    Int n1,
+    Int nn,
+    Int nempty
+)
+{
+    Int row, col ;
+    if (Diagonal_map != (Int *) NULL)
+    {
+       DEBUG2 (("\nDump the Diagonal_map: n1 "ID" nn "ID" nempty "ID"\n",
+           n1, nn, nempty)) ;
+       for (col = n1 ; col < nn - nempty ; col++)
+       {
+           row = Diagonal_map [col] ;
+           DEBUG2 (("     Diagonal_map [col = "ID"] gives "ID": ",
+               col, row)) ;
+           row = UNFLIP (row) ;
+           DEBUG2 ((" row "ID"\n", row)) ;
+           ASSERT (Diagonal_imap [row] == col) ;
+       }
+    }
+}
+
+#endif /* NDEBUG */
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_dump.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_dump.h
new file mode 100644 (file)
index 0000000..de220f3
--- /dev/null
@@ -0,0 +1,187 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* umf_dump.h: debugging definitions. */
+
+#ifndef NDEBUG
+
+GLOBAL void UMF_dump_dense
+(
+    Entry *C,
+    Int dim,
+    Int m,
+    Int n
+) ;
+
+GLOBAL void UMF_dump_element
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    Int e,
+    Int clean
+) ;
+
+GLOBAL void UMF_dump_rowcol
+(
+    Int dump_which,
+    NumericType *Numeric,
+    WorkType *Work,
+    Int dump_index,
+    Int check_degree
+) ;
+
+GLOBAL void UMF_dump_matrix
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    Int check_degree
+) ;
+
+GLOBAL void UMF_dump_current_front
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    Int check
+) ;
+
+GLOBAL void UMF_dump_lu
+(
+    NumericType *Numeric
+) ;
+
+GLOBAL void UMF_dump_memory
+(
+    NumericType *Numeric
+) ;
+
+GLOBAL void UMF_dump_packed_memory
+(
+    NumericType *Numeric,
+    WorkType *Work
+) ;
+
+GLOBAL void UMF_dump_col_matrix
+(
+    const double Ax [ ],
+#ifdef COMPLEX
+    const double Az [ ],
+#endif
+    const Int Ai [ ],
+    const Int Ap [ ],
+    Int n_row,
+    Int n_col,
+    Int nz
+) ;
+
+GLOBAL void UMF_dump_chain
+(
+    Int frontid,
+    Int Front_parent [ ],
+    Int Front_npivcol [ ],
+    Int Front_nrows [ ],
+    Int Front_ncols [ ],
+    Int nfr
+) ;
+
+GLOBAL void UMF_dump_rowmerge
+(
+    NumericType *Numeric,
+    SymbolicType *Symbolic,
+    WorkType *Work
+) ;
+
+GLOBAL void UMF_dump_start
+(
+    void
+) ;
+
+
+GLOBAL void UMF_dump_diagonal_map
+(
+    Int Diagonal_map [ ],
+    Int Diagonal_imap [ ],
+    Int n1,
+    Int nn,
+    Int nempty
+) ;
+
+#define UMF_DBMAX 50000
+GLOBAL extern Int UMF_debug ;
+GLOBAL extern Int UMF_allocfail ;
+GLOBAL extern double UMF_gprob ;
+
+#define DEBUGk(k,params) { if (UMF_debug >= (k)) { PRINTF (params) ; } }
+
+#define DEBUGm4(params) DEBUGk (-4, params)
+#define DEBUGm3(params) DEBUGk (-3, params)
+#define DEBUGm2(params) DEBUGk (-2, params)
+#define DEBUGm1(params) DEBUGk (-1, params)
+#define DEBUG0(params) DEBUGk (0, params)
+#define DEBUG1(params) DEBUGk (1, params)
+#define DEBUG2(params) DEBUGk (2, params)
+#define DEBUG3(params) DEBUGk (3, params)
+#define DEBUG4(params) DEBUGk (4, params)
+#define DEBUG5(params) DEBUGk (5, params)
+#define DEBUG6(params) DEBUGk (6, params)
+#define DEBUG7(params) DEBUGk (7, params)
+#define DEBUG8(params) DEBUGk (8, params)
+#define DEBUG9(params) DEBUGk (9, params)
+
+#define EDEBUGk(k,a) { if (UMF_debug >= (k)) { PRINT_ENTRY (a) ; } }
+
+#define EDEBUG0(a) EDEBUGk (0, a)
+#define EDEBUG1(a) EDEBUGk (1, a)
+#define EDEBUG2(a) EDEBUGk (2, a)
+#define EDEBUG3(a) EDEBUGk (3, a)
+#define EDEBUG4(a) EDEBUGk (4, a)
+#define EDEBUG5(a) EDEBUGk (5, a)
+#define EDEBUG6(a) EDEBUGk (6, a)
+#define EDEBUG7(a) EDEBUGk (7, a)
+#define EDEBUG8(a) EDEBUGk (8, a)
+#define EDEBUG9(a) EDEBUGk (9, a)
+
+/* ASSERT defined in amd_dump.h */
+
+#else
+
+/* ========================================================================== */
+/* === No debugging ========================================================= */
+/* ========================================================================== */
+
+/* turn off all debugging macros */
+
+#define DEBUGk(k,params)
+
+#define DEBUGm4(params)
+#define DEBUGm3(params)
+#define DEBUGm2(params)
+#define DEBUGm1(params)
+#define DEBUG0(params)
+#define DEBUG1(params)
+#define DEBUG2(params)
+#define DEBUG3(params)
+#define DEBUG4(params)
+#define DEBUG5(params)
+#define DEBUG6(params)
+#define DEBUG7(params)
+#define DEBUG8(params)
+#define DEBUG9(params)
+
+#define EDEBUGk(k,a)
+
+#define EDEBUG0(a)
+#define EDEBUG1(a)
+#define EDEBUG2(a)
+#define EDEBUG3(a)
+#define EDEBUG4(a)
+#define EDEBUG5(a)
+#define EDEBUG6(a)
+#define EDEBUG7(a)
+#define EDEBUG8(a)
+#define EDEBUG9(a)
+
+#endif /* NDEBUG */
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_extend_front.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_extend_front.c
new file mode 100644 (file)
index 0000000..241ed8a
--- /dev/null
@@ -0,0 +1,393 @@
+/* ========================================================================== */
+/* === UMF_extend_front ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* Called by kernel. */
+
+#include "umf_internal.h"
+#include "umf_grow_front.h"
+
+/* ========================================================================== */
+/* === zero_front =========================================================== */
+/* ========================================================================== */
+
+PRIVATE void zero_front (
+    Entry *Flblock, Entry *Fublock, Entry *Fcblock,
+    Int fnrows, Int fncols, Int fnr_curr, Int fnc_curr,
+    Int fnpiv, Int fnrows_extended, Int fncols_extended)
+{
+    Int j, i ;
+    Entry *F, *Fj, *Fi ;
+
+    Fj = Fcblock + fnrows ;
+    for (j = 0 ; j < fncols ; j++)
+    {
+       /* zero the new rows in the contribution block: */
+       F = Fj ;
+       Fj += fnr_curr ;
+#pragma ivdep
+       for (i = fnrows ; i < fnrows_extended ; i++)
+       {
+           /* CLEAR (Fcblock [i + j*fnr_curr]) ; */
+           CLEAR_AND_INCREMENT (F) ;
+       }
+    }
+
+    Fj -= fnrows ;
+    for (j = fncols ; j < fncols_extended ; j++)
+    {
+       /* zero the new columns in the contribution block: */
+       F = Fj ;
+       Fj += fnr_curr ;
+#pragma ivdep
+       for (i = 0 ; i < fnrows_extended ; i++)
+       {
+           /* CLEAR (Fcblock [i + j*fnr_curr]) ; */
+           CLEAR_AND_INCREMENT (F) ;
+       }
+    }
+
+    Fj = Flblock + fnrows ;
+    for (j = 0 ; j < fnpiv ; j++)
+    {
+       /* zero the new rows in L block: */
+       F = Fj ;
+       Fj += fnr_curr ;
+#pragma ivdep
+       for (i = fnrows ; i < fnrows_extended ; i++)
+       {
+           /* CLEAR (Flblock [i + j*fnr_curr]) ; */
+           CLEAR_AND_INCREMENT (F) ;
+       }
+    }
+
+    Fi = Fublock + fncols ;
+    for (i = 0 ; i < fnpiv ; i++)
+    {
+       /* zero the new columns in U block: */
+       F = Fi ;
+       Fi += fnc_curr ;
+#pragma ivdep
+       for (j = fncols ; j < fncols_extended ; j++)
+       {
+           /* CLEAR (Fublock [i*fnc_curr + j]) ; */
+           CLEAR_AND_INCREMENT (F) ;
+       }
+    }
+
+}
+
+/* ========================================================================== */
+/* === UMF_extend_front ===================================================== */
+/* ========================================================================== */
+
+GLOBAL Int UMF_extend_front
+(
+    NumericType *Numeric,
+    WorkType *Work
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int j, i, *Frows, row, col, *Wrow, fnr2, fnc2, *Frpos, *Fcpos, *Fcols,
+       fnrows_extended, rrdeg, ccdeg, fncols_extended, fnr_curr, fnc_curr,
+       fnrows, fncols, pos, fnpiv, *Wm ;
+    Entry *Wx, *Wy, *Fu, *Fl ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get current frontal matrix and check for frontal growth */
+    /* ---------------------------------------------------------------------- */
+
+    fnpiv = Work->fnpiv ;
+
+#ifndef NDEBUG
+    DEBUG2 (("EXTEND FRONT\n")) ;
+    DEBUG2 (("Work->fnpiv "ID"\n", fnpiv)) ;
+    ASSERT (Work->Flblock  == Work->Flublock + Work->nb*Work->nb) ;
+    ASSERT (Work->Fublock  == Work->Flblock  + Work->fnr_curr*Work->nb) ;
+    ASSERT (Work->Fcblock  == Work->Fublock  + Work->nb*Work->fnc_curr) ;
+    DEBUG7 (("C  block: ")) ;
+    UMF_dump_dense (Work->Fcblock,  Work->fnr_curr, Work->fnrows, Work->fncols) ;
+    DEBUG7 (("L  block: ")) ;
+    UMF_dump_dense (Work->Flblock,  Work->fnr_curr, Work->fnrows, fnpiv);
+    DEBUG7 (("U' block: ")) ;
+    UMF_dump_dense (Work->Fublock,  Work->fnc_curr, Work->fncols, fnpiv) ;
+    DEBUG7 (("LU block: ")) ;
+    UMF_dump_dense (Work->Flublock, Work->nb, fnpiv, fnpiv) ;
+#endif
+
+    if (Work->do_grow)
+    {
+       fnr2 = UMF_FRONTAL_GROWTH * Work->fnrows_new + 2 ;
+       fnc2 = UMF_FRONTAL_GROWTH * Work->fncols_new + 2 ;
+       if (!UMF_grow_front (Numeric, fnr2, fnc2, Work, 1))
+       {
+           DEBUGm4 (("out of memory: extend front\n")) ;
+           return (FALSE) ;
+       }
+    }
+
+    fnr_curr = Work->fnr_curr ;
+    fnc_curr = Work->fnc_curr ;
+    ASSERT (Work->fnrows_new + 1 <= fnr_curr) ;
+    ASSERT (Work->fncols_new + 1 <= fnc_curr) ;
+    ASSERT (fnr_curr >= 0 && fnr_curr % 2 == 1) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    Frows = Work->Frows ;
+    Frpos = Work->Frpos ;
+    Fcols = Work->Fcols ;
+    Fcpos = Work->Fcpos ;
+    fnrows = Work->fnrows ;
+    fncols = Work->fncols ;
+    rrdeg = Work->rrdeg ;
+    ccdeg = Work->ccdeg ;
+
+    /* scan starts at the first new column in Fcols */
+    /* also scan the pivot column if it was not in the front */
+    Work->fscan_col = fncols ;
+    Work->NewCols = Fcols ;
+
+    /* scan1 starts at the first new row in Frows */
+    /* also scan the pivot row if it was not in the front */
+    Work->fscan_row = fnrows ;
+    Work->NewRows = Frows ;
+
+    /* ---------------------------------------------------------------------- */
+    /* extend row pattern of the front with the new pivot column */
+    /* ---------------------------------------------------------------------- */
+
+    fnrows_extended = fnrows ;
+    fncols_extended = fncols ;
+
+#ifndef NDEBUG
+    DEBUG2 (("Pivot col, before extension: "ID"\n", fnrows)) ;
+    for (i = 0 ; i < fnrows ; i++)
+    {
+       DEBUG2 ((" "ID": row "ID"\n", i, Frows [i])) ;
+       ASSERT (Frpos [Frows [i]] == i) ;
+    }
+    DEBUG2 (("Extending pivot column: pivcol_in_front: "ID"\n",
+       Work->pivcol_in_front)) ;
+#endif
+
+    Fl = Work->Flblock + fnpiv * fnr_curr ;
+
+    if (Work->pivcol_in_front)
+    {
+       /* extended pattern and position already in Frows, Frpos.  Values above
+        * the diagonal are already in LU block.  Values on and below the
+        * diagonal are in Wy [0 .. fnrows_extended-1].  Copy into the L
+        * block. */
+       fnrows_extended += ccdeg ;
+       Wy = Work->Wy ;
+
+       for (i = 0 ; i < fnrows_extended ; i++)
+       {
+           Fl [i] = Wy [i] ;
+#ifndef NDEBUG
+           row = Frows [i] ;
+           DEBUG2 ((" "ID": row "ID" ", i, row)) ;
+           EDEBUG2 (Fl [i]) ;
+           if (row == Work->pivrow) DEBUG2 ((" <- pivrow")) ;
+           DEBUG2 (("\n")) ;
+           if (i == fnrows - 1) DEBUG2 ((" :::::::\n")) ;
+           ASSERT (row >= 0 && row < Work->n_row) ;
+           ASSERT (Frpos [row] == i) ;
+#endif
+       }
+
+    }
+    else
+    {
+       /* extended pattern,values is in (Wm,Wx), not yet in the front */
+       Entry *F ;
+       Fu = Work->Flublock + fnpiv * Work->nb ;
+       Wm = Work->Wm ;
+       Wx = Work->Wx ;
+       F = Fu ;
+       for (i = 0 ; i < fnpiv ; i++)
+       {
+           CLEAR_AND_INCREMENT (F) ;
+       }
+       F = Fl ;
+       for (i = 0 ; i < fnrows ; i++)
+       {
+           CLEAR_AND_INCREMENT (F) ;
+       }
+       for (i = 0 ; i < ccdeg ; i++)
+       {
+           row = Wm [i] ;
+#ifndef NDEBUG
+           DEBUG2 ((" "ID": row "ID" (ext) ", fnrows_extended, row)) ;
+           EDEBUG2 (Wx [i]) ;
+           if (row == Work->pivrow) DEBUG2 ((" <- pivrow")) ;
+           DEBUG2 (("\n")) ;
+           ASSERT (row >= 0 && row < Work->n_row) ;
+#endif
+           pos = Frpos [row] ;
+           if (pos < 0)
+           {
+               pos = fnrows_extended++ ;
+               Frows [pos] = row ;
+               Frpos [row] = pos ;
+           }
+           Fl [pos] = Wx [i] ;
+       }
+    }
+
+    ASSERT (fnrows_extended <= fnr_curr) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* extend the column pattern of the front with the new pivot row */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    DEBUG6 (("Pivot row, before extension: "ID"\n", fncols)) ;
+    for (j = 0 ; j < fncols ; j++)
+    {
+       DEBUG7 ((" "ID": col "ID"\n", j, Fcols [j])) ;
+       ASSERT (Fcpos [Fcols [j]] == j * fnr_curr) ;
+    }
+    DEBUG6 (("Extending pivot row:\n")) ;
+#endif
+
+    if (Work->pivrow_in_front)
+    {
+       if (Work->pivcol_in_front)
+       {
+           ASSERT (Fcols == Work->Wrow) ;
+           for (j = fncols ; j < rrdeg ; j++)
+           {
+#ifndef NDEBUG
+               col = Fcols [j] ;
+               DEBUG2 ((" "ID": col "ID" (ext)\n", j, col)) ;
+               ASSERT (col != Work->pivcol) ;
+               ASSERT (col >= 0 && col < Work->n_col) ;
+               ASSERT (Fcpos [col] < 0) ;
+#endif
+               Fcpos [Fcols [j]] = j * fnr_curr ;
+           }
+       }
+       else
+       {
+           /* OUT-IN option: pivcol not in front, but pivrow is in front */
+           Wrow = Work->Wrow ;
+           ASSERT (IMPLIES (Work->pivcol_in_front, Wrow == Fcols)) ;
+           if (Wrow == Fcols)
+           {
+               /* Wrow and Fcols are equivalenced */
+               for (j = fncols ; j < rrdeg ; j++)
+               {
+                   col = Wrow [j] ;
+                   DEBUG2 ((" "ID": col "ID" (ext)\n", j, col)) ;
+                   ASSERT (Fcpos [col] < 0) ;
+                   /* Fcols [j] = col ;  not needed */
+                   Fcpos [col] = j * fnr_curr ;
+               }
+           }
+           else
+           {
+               for (j = fncols ; j < rrdeg ; j++)
+               {
+                   col = Wrow [j] ;
+                   DEBUG2 ((" "ID": col "ID" (ext)\n", j, col)) ;
+                   ASSERT (Fcpos [col] < 0) ;
+                   Fcols [j] = col ;
+                   Fcpos [col] = j * fnr_curr ;
+               }
+           }
+       }
+       fncols_extended = rrdeg ;
+    }
+    else
+    {
+       ASSERT (Fcols != Work->Wrow) ;
+       Wrow = Work->Wrow ;
+       for (j = 0 ; j < rrdeg ; j++)
+       {
+           col = Wrow [j] ;
+           ASSERT (col >= 0 && col < Work->n_col) ;
+           if (Fcpos [col] < 0)
+           {
+               DEBUG2 ((" col:: "ID" (ext)\n", col)) ;
+               Fcols [fncols_extended] = col ;
+               Fcpos [col] = fncols_extended * fnr_curr ;
+               fncols_extended++ ;
+           }
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* pivot row and column have been extended */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    ASSERT (fncols_extended <= fnc_curr) ;
+    ASSERT (fnrows_extended <= fnr_curr) ;
+
+    DEBUG6 (("Pivot col, after ext: "ID" "ID"\n", fnrows,fnrows_extended)) ;
+    for (i = 0 ; i < fnrows_extended ; i++)
+    {
+       row = Frows [i] ;
+       DEBUG7 ((" "ID": row "ID" pos "ID" old: %d", i, row, Frpos [row],
+           i < fnrows)) ;
+       if (row == Work->pivrow ) DEBUG7 (("  <-- pivrow")) ;
+       DEBUG7 (("\n")) ;
+       ASSERT (Frpos [Frows [i]] == i) ;
+    }
+
+    DEBUG6 (("Pivot row position: "ID"\n", Frpos [Work->pivrow])) ;
+    ASSERT (Frpos [Work->pivrow] >= 0) ;
+    ASSERT (Frpos [Work->pivrow] < fnrows_extended) ;
+
+    DEBUG6 (("Pivot row, after ext: "ID" "ID"\n", fncols,fncols_extended)) ;
+    for (j = 0 ; j < fncols_extended ; j++)
+    {
+       col = Fcols [j] ;
+       DEBUG7 ((" "ID": col "ID" pos "ID" old: %d", j, col, Fcpos [col],
+           j < fncols)) ;
+       if (col == Work->pivcol ) DEBUG7 (("  <-- pivcol")) ;
+       DEBUG7 (("\n")) ;
+       ASSERT (Fcpos [Fcols [j]] == j * fnr_curr) ;
+    }
+
+    DEBUG6 (("Pivot col position: "ID"\n", Fcpos [Work->pivcol])) ;
+    ASSERT (Fcpos [Work->pivcol] >= 0) ;
+    ASSERT (Fcpos [Work->pivcol] < fncols_extended * fnr_curr) ;
+
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* Zero the newly extended frontal matrix */
+    /* ---------------------------------------------------------------------- */
+
+    zero_front (Work->Flblock, Work->Fublock, Work->Fcblock,
+       fnrows, fncols, fnr_curr, fnc_curr,
+       fnpiv, fnrows_extended, fncols_extended) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* finalize extended row and column pattern of the frontal matrix */
+    /* ---------------------------------------------------------------------- */
+
+    Work->fnrows = fnrows_extended ;
+    Work->fncols = fncols_extended ;
+
+    ASSERT (fnrows_extended == Work->fnrows_new + 1) ;
+    ASSERT (fncols_extended == Work->fncols_new + 1) ;
+
+    return (TRUE) ;
+
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_extend_front.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_extend_front.h
new file mode 100644 (file)
index 0000000..45e3d47
--- /dev/null
@@ -0,0 +1,12 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_extend_front
+(
+    NumericType *Numeric,
+    WorkType *Work
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_free.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_free.c
new file mode 100644 (file)
index 0000000..5f74ae9
--- /dev/null
@@ -0,0 +1,46 @@
+/* ========================================================================== */
+/* === UMF_free ============================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Free a block previously allocated by UMF_malloc and return NULL.
+    Usage is p = UMF_free (p), to ensure that we don't free it twice.
+    Also maintains the UMFPACK malloc count.
+*/
+
+#include "umf_internal.h"
+
+#if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG)
+#include "umf_malloc.h"
+#endif
+
+GLOBAL void *UMF_free
+(
+    void *p
+)
+{
+    DEBUG0 (("UMF_free: "ID"\n", (Int) p)) ;
+    if (p)
+    {
+
+       /* see umf_config.h for the memory allocator selection */
+       FREE (p) ;
+
+#if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG)
+       /* One more object has been free'd.  Keep track of the count. */
+       /* (purely for sanity checks). */
+       UMF_malloc_count-- ;
+       DEBUG0 (("     new malloc count: "ID"\n", UMF_malloc_count)) ;
+#endif
+
+    }
+
+    return ((void *) NULL) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_free.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_free.h
new file mode 100644 (file)
index 0000000..b2bf660
--- /dev/null
@@ -0,0 +1,11 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void *UMF_free
+(
+    void *p
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_fsize.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_fsize.c
new file mode 100644 (file)
index 0000000..ceaf648
--- /dev/null
@@ -0,0 +1,70 @@
+/* ========================================================================== */
+/* === UMF_fsize ============================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* Determine the largest frontal matrix size for each subtree.   Called by
+ * UMF_colamd and UMF_analyze.  Only required to sort the children of each
+ * node prior to AMD_postorder. */
+
+#include "umf_internal.h"
+
+GLOBAL void UMF_fsize
+(
+    Int nn,
+    Int Fsize [ ],
+    Int Fnrows [ ],
+    Int Fncols [ ],
+    Int Parent [ ],
+    Int Npiv [ ]
+)
+{
+    Int j, parent, frsize, r, c ;
+
+    for (j = 0 ; j < nn ; j++)
+    {
+       Fsize [j] = EMPTY ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* find max front size for tree rooted at node j, for each front j */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG1 (("\n\n========================================FRONTS:\n")) ;
+    for (j = 0 ; j < nn ; j++)
+    {
+       if (Npiv [j] > 0)
+       {
+           /* this is a frontal matrix */
+           parent = Parent [j] ;
+           r = Fnrows [j] ;
+           c = Fncols [j] ;
+           frsize = r * c ;
+           /* avoid integer overflow */
+           if (INT_OVERFLOW (((double) r) * ((double) c)))
+           {
+               /* :: frsize int overflow :: */
+               frsize = Int_MAX ;
+           }
+           DEBUG1 ((""ID" : npiv "ID" size "ID" parent "ID" ",
+               j, Npiv [j], frsize, parent)) ;
+           Fsize [j] = MAX (Fsize [j], frsize) ;
+           DEBUG1 (("Fsize [j = "ID"] = "ID"\n", j, Fsize [j])) ;
+           if (parent != EMPTY)
+           {
+               /* find the maximum frontsize of self and children */
+               ASSERT (Npiv [parent] > 0) ;
+               ASSERT (parent > j) ;
+               Fsize [parent] = MAX (Fsize [parent], Fsize [j]) ;
+               DEBUG1 (("Fsize [parent = "ID"] = "ID"\n",
+                   parent, Fsize [parent]));
+           }
+       }
+    }
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_fsize.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_fsize.h
new file mode 100644 (file)
index 0000000..cef2ad9
--- /dev/null
@@ -0,0 +1,16 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_fsize
+(
+    Int nn,
+    Int MaxFsize [ ],
+    Int Fnrows [ ],
+    Int Fncols [ ],
+    Int Parent [ ],
+    Int Npiv [ ]
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_garbage_collection.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_garbage_collection.c
new file mode 100644 (file)
index 0000000..abaf180
--- /dev/null
@@ -0,0 +1,696 @@
+/* ========================================================================== */
+/* === UMF_garbage_collection =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Compress the elements at the tail of Numeric->Memory, and delete the tuples.
+    Elements are renumbered.  The new numbering space is compressed, and
+    in the order of element creation (original elements of A first, followed
+    by the new elements in the order that they were formed).
+
+    Only called by UMF_get_memory.
+
+    There are 5 ways in which garbage collection can be performed:
+
+       Allocate a new working array for the current frontal matrix.  In this
+       case, there are never any pivot rows/columns in the current frontal
+       matrix (fnpiv = 0), and the old working array for the current frontal
+       matrix can always be fully compacted, to fnrows-by-fncols.
+
+           UMF_kernel : UMF_extend : UMF_grow_front : UMF_get_memory
+           UMF_kernel : UMF_init_front : UMF_grow_front : UMF_get_memory
+           UMF_kernel : UMF_start_front : UMF_grow_front : UMF_get_memory
+
+       Allocate a new element.  In this case, UMF_grow_front may or may not
+       be subsequently called, depending on Work->do_grow.  There are never
+       any pivot rows/columns in the current frontal matrix (fnpiv=0), but one
+       may be added if UMF_init_front is to be called just after
+       UMF_create_element.  If do_grow is true, then the current front can be
+       fully compacted, to fnrows-by-fncols.  Otherwise, it can only be
+       partially compacted, to MAX (fnrows, fnrows_new + 1) -by-
+       MAX (fncols, fncols_new + 1).
+
+           UMF_kernel : UMF_create_element : UMF_get_memory
+
+       Allocate rows of L and columns of U.  In this case, the current
+       frontal matrix is only partially compacted, to (fnrows_new + 1)-by-
+       (fncols_new + 1).  There are pivots in the frontal matrix (fnpiv > 0).
+
+           UMF_kernel : UMF_store_lu : UMF_get_memory
+*/
+
+#include "umf_internal.h"
+
+GLOBAL void UMF_garbage_collection
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    Int drnew,     /* compact current front to drnew-by-dcnew */
+    Int dcnew,
+    Int do_Fcpos
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int size, e, n_row, n_col, nrows, ncols, nrowsleft, ncolsleft, prevsize,
+       csize, size2, i2, j2, i, j, cdeg, rdeg, *E, row, col,
+       *Rows, *Cols, *Rows2, *Cols2, nel, e2, *Row_tuples, *Col_tuples,
+       *Row_degree, *Col_degree ;
+    Entry *C, *C1, *C3, *C2 ;
+    Unit *psrc, *pdest, *p, *pnext ;
+    Element *epsrc, *epdest ;
+
+#ifndef NDEBUG
+    Int nmark ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    Col_degree = Numeric->Cperm ;      /* for NON_PIVOTAL_COL macro */
+    Row_degree = Numeric->Rperm ;      /* for NON_PIVOTAL_ROW macro */
+    Row_tuples = Numeric->Uip ;
+    Col_tuples = Numeric->Lip ;
+    E = Work->E ;
+    n_row = Work->n_row ;
+    n_col = Work->n_col ;
+
+    /* note that the tuple lengths (Col_tlen and Row_tlen) are updated, but */
+    /* the tuple lists themselves are stale and are about to be destroyed */
+    /* and recreated.  Do not attempt to scan them until they are recreated. */
+
+#ifndef NDEBUG
+    DEBUGm1 (("::::GARBAGE COLLECTION::::\n")) ;
+    UMF_dump_memory (Numeric) ;
+#endif
+
+    Numeric->ngarbage++ ;
+
+    /* ---------------------------------------------------------------------- */
+    /* delete the tuple lists by marking the blocks as free */
+    /* ---------------------------------------------------------------------- */
+
+    /* do not modify Row_tlen and Col_tlen */
+    /* those are needed for UMF_build_tuples */
+
+    for (row = 0 ; row < n_row ; row++)
+    {
+       if (NON_PIVOTAL_ROW (row) && Row_tuples [row])
+       {
+           DEBUG2 (("row "ID" tuples "ID"\n", row, Row_tuples [row])) ;
+           p = Numeric->Memory + Row_tuples [row] - 1 ;
+           DEBUG2 (("Freeing tuple list row "ID", p-S "ID", size "ID"\n",
+               row, (Int) (p-Numeric->Memory), p->header.size)) ;
+           ASSERT (p->header.size > 0) ;
+           ASSERT (p >= Numeric->Memory + Numeric->itail) ;
+           ASSERT (p < Numeric->Memory + Numeric->size) ;
+           p->header.size = -p->header.size ;
+           Row_tuples [row] = 0 ;
+       }
+    }
+
+    for (col = 0 ; col < n_col ; col++)
+    {
+       if (NON_PIVOTAL_COL (col) && Col_tuples [col])
+       {
+           DEBUG2 (("col "ID" tuples "ID"\n", col, Col_tuples [col])) ;
+           p = Numeric->Memory + Col_tuples [col] - 1 ;
+           DEBUG2 (("Freeing tuple list col "ID", p-S "ID", size "ID"\n",
+               col, (Int) (p-Numeric->Memory), p->header.size)) ;
+           ASSERT (p->header.size > 0) ;
+           ASSERT (p >= Numeric->Memory + Numeric->itail) ;
+           ASSERT (p < Numeric->Memory + Numeric->size) ;
+           p->header.size = -p->header.size ;
+           Col_tuples [col] = 0 ;
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* mark the elements, and compress the name space */
+    /* ---------------------------------------------------------------------- */
+
+    nel = Work->nel ;
+    ASSERT (nel < Work->elen) ;
+
+#ifndef NDEBUG
+    nmark = 0 ;
+    UMF_dump_current_front (Numeric, Work, FALSE) ;
+    DEBUGm1 (("E [0] "ID"  \n", E [0])) ;
+    ASSERT (IMPLIES (E [0],
+               Work->Flublock == (Entry *) (Numeric->Memory + E [0]))) ;
+    ASSERT (IMPLIES (Work->Flublock,
+               Work->Flublock == (Entry *) (Numeric->Memory + E [0]))) ;
+    ASSERT ((E [0] != 0) == (Work->Flublock != (Entry *) NULL)) ;
+#endif
+
+    e2 = 0 ;
+
+    for (e = 0 ; e <= nel ; e++) /* for all elements in order of creation */
+    {
+       if (E [e])
+       {
+           psrc = Numeric->Memory + E [e] ;
+           psrc-- ;            /* get the header of this block */
+           if (e > 0)
+           {
+               e2++ ;  /* do not renumber element zero */
+           }
+           ASSERT (psrc->header.size > 0) ;
+           psrc->header.size = e2  ;   /* store the new name in the header */
+#ifndef NDEBUG
+           nmark++ ;
+#endif
+           DEBUG7 ((ID":: Mark e "ID" at psrc-S "ID", new e "ID"\n",
+               nmark, e, (Int) (psrc-Numeric->Memory), e2)) ;
+           E [e] = 0 ;
+           if (e == Work->prior_element)
+           {
+               Work->prior_element = e2 ;
+           }
+       }
+    }
+
+    /* all 1..e2 are now in use (element zero may or may not be in use) */
+    Work->nel = e2 ;
+    nel = Work->nel ;
+
+#ifndef NDEBUG
+    for (e = 0 ; e < Work->elen ; e++)
+    {
+       ASSERT (!E [e]) ;
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* compress the elements */
+    /* ---------------------------------------------------------------------- */
+
+    /* point to tail marker block of size 1 + header */
+    psrc = Numeric->Memory + Numeric->size - 2 ;
+    pdest = psrc ;
+    prevsize = psrc->header.prevsize ;
+    DEBUG7 (("Starting the compression:\n")) ;
+
+    while (prevsize > 0)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* move up to the next element above the current header, and */
+       /* get the element name and size */
+       /* (if it is an element, the name will be positive) */
+       /* ------------------------------------------------------------------ */
+
+       size = prevsize ;
+       psrc -= (size + 1) ;
+       e = psrc->header.size ;
+       prevsize = psrc->header.prevsize ;
+       /* top block at tail has prevsize of 0 */
+
+       /* a free block will have a negative size, so skip it */
+       /* otherwise, if size >= 0, it holds the element name, not the size */
+
+       DEBUG8 (("psrc-S: "ID" prevsize: "ID" size: "ID,
+           (Int) (psrc-Numeric->Memory), prevsize, size)) ;
+
+       if (e == 0)
+       {
+           /* -------------------------------------------------------------- */
+           /* this is the current frontal matrix */
+           /* -------------------------------------------------------------- */
+
+           Entry *F1, *F2, *Fsrc, *Fdst ;
+           Int c, r, k, dr, dc, gap, gap1, gap2, nb ;
+
+           /* shift the frontal matrix down */
+           F1 = (Entry *) (psrc + 1) ;
+
+           /* get the size of the current front.  r and c could be zero */
+           k = Work->fnpiv ;
+           dr = Work->fnr_curr ;
+           dc = Work->fnc_curr ;
+           r = Work->fnrows ;
+           c = Work->fncols ;
+           nb = Work->nb ;
+
+           ASSERT ((dr >= 0 && (dr % 2) == 1) || dr == 0) ;
+           ASSERT (drnew >= 0) ;
+           if (drnew % 2 == 0)
+           {
+               /* make sure leading frontal matrix dimension is always odd */
+               drnew++ ;
+           }
+           drnew = MIN (dr, drnew) ;
+           ASSERT ((drnew >= 0 && (drnew % 2) == 1) || drnew == 0) ;
+
+           pnext = pdest ;
+
+#ifndef NDEBUG
+           DEBUGm2 (("move front: dr "ID" dc "ID" r "ID" drnew "ID" c "ID
+               " dcnew " ID" k "ID"\n", dr, dc, r, drnew, c, dcnew, k)) ;
+           DEBUG7 (("\n")) ;
+           DEBUG7 ((ID":: Move current frontal matrix from: psrc-S: "ID" \n",
+               nmark, (Int) (psrc-Numeric->Memory))) ;
+           nmark-- ;
+           ASSERT (E [e] == 0) ;
+           ASSERT (Work->Flublock == F1) ;
+           ASSERT (Work->Flblock  == Work->Flublock + nb*nb) ;
+           ASSERT (Work->Fublock  == Work->Flblock  + dr*nb) ;
+           ASSERT (Work->Fcblock  == Work->Fublock  + nb*dc) ;
+           DEBUG7 (("C  block: ")) ;
+           UMF_dump_dense (Work->Fcblock,  dr, r, c) ;
+           DEBUG7 (("L  block: ")) ;
+           UMF_dump_dense (Work->Flblock,  dr, r, k);
+           DEBUG7 (("U' block: ")) ;
+           UMF_dump_dense (Work->Fublock,  dc, c, k) ;
+           DEBUG7 (("LU block: ")) ;
+           UMF_dump_dense (Work->Flublock, nb, k, k) ;
+           ASSERT (r <= drnew && c <= dcnew && drnew <= dr && dcnew <= dc) ;
+#endif
+
+           /* compact frontal matrix to drnew-by-dcnew before moving it */
+
+           /* do not compact the LU block (nb-by-nb) */
+
+           /* compact the columns of L (from dr-by-nb to drnew-by-nb) */
+           Fsrc = Work->Flblock ;
+           Fdst = Work->Flblock ;
+           ASSERT (Fdst == F1 + nb*nb) ;
+           gap1 = dr - r ;
+           gap2 = drnew - r ;
+           ASSERT (gap1 >= 0) ;
+           for (j = 0 ; j < k ; j++)
+           {
+               for (i = 0 ; i < r ; i++)
+               {
+                   *Fdst++ = *Fsrc++ ;
+               }
+               Fsrc += gap1 ;
+               Fdst += gap2 ;
+           }
+           ASSERT (Fdst == F1 + nb*nb + drnew*k) ;
+           Fdst += drnew * (nb - k) ;
+
+           /* compact the rows of U (U' from dc-by-nb to dcnew-by-nb) */
+           Fsrc = Work->Fublock ;
+           ASSERT (Fdst == F1 + nb*nb + drnew*nb) ;
+           gap1 = dc - c ;
+           gap2 = dcnew - c ;
+           for (i = 0 ; i < k ; i++)
+           {
+               for (j = 0 ; j < c ; j++)
+               {
+                   *Fdst++ = *Fsrc++ ;
+               }
+               Fsrc += gap1 ;
+               Fdst += gap2 ;
+           }
+           ASSERT (Fdst == F1 + nb*nb + drnew*nb + dcnew*k) ;
+           Fdst += dcnew * (nb - k) ;
+
+           /* compact the columns of C (from dr-by-dc to drnew-by-dcnew) */
+           Fsrc = Work->Fcblock ;
+           ASSERT (Fdst == F1 + nb*nb + drnew*nb + nb*dcnew) ;
+           gap1 = dr - r ;
+           gap2 = drnew - r ;
+           for (j = 0 ; j < c ; j++)
+           {
+               for (i = 0 ; i < r ; i++)
+               {
+                   *Fdst++ = *Fsrc++ ;
+               }
+               Fsrc += gap1 ;
+               Fdst += gap2 ;
+           }
+           ASSERT (Fdst == F1 + nb*nb + drnew*nb + nb*dcnew + drnew*c) ;
+
+           /* recompute Fcpos, if necessary */
+           if (do_Fcpos)
+           {
+               Int *Fcols, *Fcpos ;
+               Fcols = Work->Fcols ;
+               Fcpos = Work->Fcpos ;
+               for (j = 0 ; j < c ; j++)
+               {
+                   col = Fcols [j] ;
+                   ASSERT (col >= 0 && col < Work->n_col) ;
+                   ASSERT (Fcpos [col] == j * dr) ;
+                   Fcpos [col] = j * drnew ;
+               }
+#ifndef NDEBUG
+               {
+                   Int cnt = 0 ;
+                   for (j = 0 ; j < Work->n_col ; j++)
+                   {
+                       if (Fcpos [j] != EMPTY) cnt++ ;
+                   }
+                   DEBUGm2 (("Recompute Fcpos cnt "ID" c "ID"\n", cnt, c)) ;
+                   ASSERT (cnt == c) ;
+               }
+#endif
+           }
+
+#ifndef NDEBUG
+           DEBUGm2 (("Compacted front, drnew "ID" dcnew "ID"\n", drnew, dcnew)) ;
+           DEBUG7 (("C  block: ")) ;
+           UMF_dump_dense (F1 + nb*nb + drnew*nb + nb*dcnew, drnew, r, c) ;
+           DEBUG7 (("L  block: ")) ;
+           UMF_dump_dense (F1 + nb*nb, drnew, r, k) ;
+           DEBUG7 (("U  block: ")) ;
+           UMF_dump_dense (F1 + nb*nb + drnew*nb, nb, k, c) ;
+           DEBUG7 (("LU block: ")) ;
+           UMF_dump_dense (F1, nb, k, k) ;
+#endif
+
+           /* Compacted dimensions of the new frontal matrix. */
+           Work->fnr_curr = drnew ;
+           Work->fnc_curr = dcnew ;
+           Work->fcurr_size = (drnew + nb) * (dcnew + nb) ;
+           size = UNITS (Entry, Work->fcurr_size) ;
+
+           /* make sure the object doesn't evaporate.  The front can have
+            * zero size (Work->fcurr_size = 0), but the size of the memory
+            * block containing it cannot have zero size. */
+           size = MAX (1, size) ;
+
+           /* get the destination of frontal matrix */
+           pnext->header.prevsize = size ;
+           pdest -= (size + 1) ;
+           F2 = (Entry *) (pdest + 1) ;
+
+           ASSERT ((unsigned Int) psrc + 1 + size <= (unsigned Int) pnext) ;
+           ASSERT (psrc <= pdest) ;
+           ASSERT (F1 <= F2) ;
+
+           /* move the C block first */
+           Fsrc = F1 + nb*nb + drnew*nb + nb*dcnew + drnew*c ;
+           Fdst = F2 + nb*nb + drnew*nb + nb*dcnew + drnew*c ;
+           gap = drnew - r ;
+           for (j = c-1 ; j >= 0 ; j--)
+           {
+               Fsrc -= gap ;
+               Fdst -= gap ;
+               /* move column j of C */
+               for (i = r-1 ; i >= 0 ; i--)
+               {
+                   *--Fdst = *--Fsrc ;
+               }
+           }
+           ASSERT (Fsrc == F1 + nb*nb + drnew*nb + nb*dcnew) ;
+           ASSERT (Fdst == F2 + nb*nb + drnew*nb + nb*dcnew) ;
+
+           /* move the U block */
+           Fsrc -= dcnew * (nb - k) ;
+           Fdst -= dcnew * (nb - k) ;
+           ASSERT (Fsrc == F1 + nb*nb + drnew*nb + dcnew*k) ;
+           ASSERT (Fdst == F2 + nb*nb + drnew*nb + dcnew*k) ;
+           gap = dcnew - c ;
+           for (i = k-1 ; i >= 0 ; i--)
+           {
+               Fsrc -= gap ;
+               Fdst -= gap ;
+               for (j = c-1 ; j >= 0 ; j--)
+               {
+                   *--Fdst = *--Fsrc ;
+               }
+           }
+           ASSERT (Fsrc == F1 + nb*nb + drnew*nb) ;
+           ASSERT (Fdst == F2 + nb*nb + drnew*nb) ;
+
+           /* move the L block */
+           Fsrc -= drnew * (nb - k) ;
+           Fdst -= drnew * (nb - k) ;
+           ASSERT (Fsrc == F1 + nb*nb + drnew*k) ;
+           ASSERT (Fdst == F2 + nb*nb + drnew*k) ;
+           gap = drnew - r ;
+           for (j = k-1 ; j >= 0 ; j--)
+           {
+               Fsrc -= gap ;
+               Fdst -= gap ;
+               for (i = r-1 ; i >= 0 ; i--)
+               {
+                   *--Fdst = *--Fsrc ;
+               }
+           }
+           ASSERT (Fsrc == F1 + nb*nb) ;
+           ASSERT (Fdst == F2 + nb*nb) ;
+
+           /* move the LU block */
+           Fsrc -= nb * (nb - k) ;
+           Fdst -= nb * (nb - k) ;
+           ASSERT (Fsrc == F1 + nb*k) ;
+           ASSERT (Fdst == F2 + nb*k) ;
+           gap = nb - k ;
+           for (j = k-1 ; j >= 0 ; j--)
+           {
+               Fsrc -= gap ;
+               Fdst -= gap ;
+               for (i = k-1 ; i >= 0 ; i--)
+               {
+                   *--Fdst = *--Fsrc ;
+               }
+           }
+           ASSERT (Fsrc == F1) ;
+           ASSERT (Fdst == F2) ;
+
+           E [0] = (pdest + 1) - Numeric->Memory ;
+
+           Work->Flublock = (Entry *) (Numeric->Memory + E [0]) ;
+           ASSERT (Work->Flublock == F2) ;
+           Work->Flblock  = Work->Flublock + nb * nb ;
+           Work->Fublock  = Work->Flblock  + drnew * nb ;
+           Work->Fcblock  = Work->Fublock  + nb * dcnew ;
+
+           pdest->header.prevsize = 0 ;
+           pdest->header.size = size ;
+
+#ifndef NDEBUG
+           DEBUG7 (("After moving compressed current frontal matrix:\n")) ;
+           DEBUG7 (("C  block: ")) ;
+           UMF_dump_dense (Work->Fcblock,  drnew, r, c) ;
+           DEBUG7 (("L  block: ")) ;
+           UMF_dump_dense (Work->Flblock,  drnew, r, k);
+           DEBUG7 (("U' block: ")) ;
+           UMF_dump_dense (Work->Fublock,  dcnew, c, k) ;
+           DEBUG7 (("LU block: ")) ;
+           UMF_dump_dense (Work->Flublock, nb, k, k) ;
+#endif
+
+       }
+       else if (e > 0)
+       {
+
+           /* -------------------------------------------------------------- */
+           /* this is an element, compress and move from psrc down to pdest */
+           /* -------------------------------------------------------------- */
+
+#ifndef NDEBUG
+           DEBUG7 (("\n")) ;
+           DEBUG7 ((ID":: Move element "ID": from: "ID" \n",
+               nmark, e, (Int) (psrc-Numeric->Memory))) ;
+           nmark-- ;
+           ASSERT (e <= nel) ;
+           ASSERT (E [e] == 0) ;
+#endif
+
+           /* -------------------------------------------------------------- */
+           /* get the element scalars, and pointers to C, Rows, and Cols: */
+           /* -------------------------------------------------------------- */
+
+           p = psrc + 1 ;
+           GET_ELEMENT (epsrc, p, Cols, Rows, ncols, nrows, C) ;
+           nrowsleft = epsrc->nrowsleft ;
+           ncolsleft = epsrc->ncolsleft ;
+           cdeg = epsrc->cdeg ;
+           rdeg = epsrc->rdeg ;
+
+#ifndef NDEBUG
+           DEBUG7 ((" nrows "ID" nrowsleft "ID"\n", nrows, nrowsleft)) ;
+           DEBUG7 ((" ncols "ID" ncolsleft "ID"\n", ncols, ncolsleft)) ;
+           DEBUG8 ((" Rows:")) ;
+           for (i = 0 ; i < nrows ; i++) DEBUG8 ((" "ID, Rows [i])) ;
+           DEBUG8 (("\n Cols:")) ;
+           for (j = 0 ; j < ncols ; j++) DEBUG8 ((" "ID, Cols [j])) ;
+           DEBUG8 (("\n")) ;
+#endif
+
+           /* -------------------------------------------------------------- */
+           /* determine the layout of the new element */
+           /* -------------------------------------------------------------- */
+
+           csize = nrowsleft * ncolsleft ;
+           size2 = UNITS (Element, 1)
+                 + UNITS (Int, nrowsleft + ncolsleft)
+                 + UNITS (Entry, csize) ;
+
+           DEBUG7 (("Old size "ID" New size "ID"\n", size, size2)) ;
+
+           pnext = pdest ;
+           pnext->header.prevsize = size2 ;
+           pdest -= (size2 + 1) ;
+
+           ASSERT (size2 <= size) ;
+           ASSERT ((unsigned Int) psrc + 1 + size <= (unsigned Int) pnext) ;
+           ASSERT (psrc <= pdest) ;
+
+           p = pdest + 1 ;
+           epdest = (Element *) p ;
+           p += UNITS (Element, 1) ;
+           Cols2 = (Int *) p ;
+           Rows2 = Cols2 + ncolsleft ;
+           p += UNITS (Int, nrowsleft + ncolsleft) ;
+           C2 = (Entry *) p ;
+
+           ASSERT (epdest >= epsrc) ;
+           ASSERT (Rows2 >= Rows) ;
+           ASSERT (Cols2 >= Cols) ;
+           ASSERT (C2 >= C) ;
+           ASSERT (p + UNITS (Entry, csize) == pnext) ;
+
+           /* -------------------------------------------------------------- */
+           /* move the contribution block */
+           /* -------------------------------------------------------------- */
+
+           /* overlap = psrc + size + 1 > pdest ; */
+
+           if (nrowsleft < nrows || ncolsleft < ncols)
+           {
+
+               /* ---------------------------------------------------------- */
+               /* compress contribution block in place prior to moving it */
+               /* ---------------------------------------------------------- */
+
+               DEBUG7 (("Compress C in place prior to move:\n"));
+#ifndef NDEBUG
+               UMF_dump_dense (C, nrows, nrows, ncols) ;
+#endif
+               C1 = C ;
+               C3 = C ;
+               for (j = 0 ; j < ncols ; j++)
+               {
+                   if (Cols [j] >= 0)
+                   {
+                       for (i = 0 ; i < nrows ; i++)
+                       {
+                           if (Rows [i] >= 0)
+                           {
+                               *C3++ = C1 [i] ;
+                           }
+                       }
+                   }
+                   C1 += nrows ;
+               }
+               ASSERT (C3-C == csize) ;
+               DEBUG8 (("Newly compressed contrib. block (all in use):\n")) ;
+#ifndef NDEBUG
+               UMF_dump_dense (C, nrowsleft, nrowsleft, ncolsleft) ;
+#endif
+           }
+
+           /* shift the contribution block down */
+           C += csize ;
+           C2 += csize ;
+           for (i = 0 ; i < csize ; i++)
+           {
+               *--C2 = *--C ;
+           }
+
+           /* -------------------------------------------------------------- */
+           /* move the row indices */
+           /* -------------------------------------------------------------- */
+
+           i2 = nrowsleft ;
+           for (i = nrows - 1 ; i >= 0 ; i--)
+           {
+               ASSERT (Rows2+i2 >= Rows+i) ;
+               if (Rows [i] >= 0)
+               {
+                   Rows2 [--i2] = Rows [i] ;
+               }
+           }
+           ASSERT (i2 == 0) ;
+
+           j2 = ncolsleft ;
+           for (j = ncols - 1 ; j >= 0 ; j--)
+           {
+               ASSERT (Cols2+j2 >= Cols+j) ;
+               if (Cols [j] >= 0)
+               {
+                   Cols2 [--j2] = Cols [j] ;
+               }
+           }
+           ASSERT (j2 == 0) ;
+
+           /* -------------------------------------------------------------- */
+           /* construct the new header */
+           /* -------------------------------------------------------------- */
+
+           /* E [0...e] is now valid */
+           E [e] = (pdest + 1) - Numeric->Memory ;
+           epdest = (Element *) (pdest + 1) ;
+
+           epdest->next = EMPTY ;      /* destroys the son list */
+           epdest->ncols = ncolsleft ;
+           epdest->nrows = nrowsleft ;
+           epdest->ncolsleft = ncolsleft ;
+           epdest->nrowsleft = nrowsleft ;
+           epdest->rdeg = rdeg ;
+           epdest->cdeg = cdeg ;
+
+           ASSERT (size2 <= size) ;
+           pdest->header.prevsize = 0 ;
+           pdest->header.size = size2 ;
+
+           DEBUG7 (("After moving it:\n")) ;
+#ifndef NDEBUG
+           UMF_dump_element (Numeric, Work, e, FALSE) ;
+#endif
+       }
+
+#ifndef NDEBUG
+       else
+       {
+           DEBUG8 ((" free\n")) ;
+       }
+#endif
+       DEBUG7 (("psrc "ID"  tail "ID"\n",
+       (Int) (psrc-Numeric->Memory), Numeric->itail)) ;
+    }
+
+    ASSERT (psrc == Numeric->Memory + Numeric->itail) ;
+    ASSERT (nmark == 0) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* final tail pointer */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (pdest >= Numeric->Memory + Numeric->itail) ;
+    Numeric->itail = pdest - Numeric->Memory ;
+    pdest->header.prevsize = 0 ;
+    Numeric->ibig = EMPTY ;
+    Numeric->tail_usage = Numeric->size - Numeric->itail ;
+
+    /* ---------------------------------------------------------------------- */
+    /* clear the unused E [nel+1 .. Work->elen - 1] */
+    /* ---------------------------------------------------------------------- */
+
+    for (e = nel+1 ; e < Work->elen ; e++)
+    {
+       E [e] = 0 ;
+    }
+
+#ifndef NDEBUG
+    UMF_dump_packed_memory (Numeric, Work) ;
+#endif
+
+    DEBUG8 (("::::GARBAGE COLLECTION DONE::::\n")) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_garbage_collection.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_garbage_collection.h
new file mode 100644 (file)
index 0000000..29d9186
--- /dev/null
@@ -0,0 +1,15 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_garbage_collection
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    Int drnew,
+    Int dcnew,
+    Int do_Fcpos
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_get_memory.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_get_memory.c
new file mode 100644 (file)
index 0000000..480288b
--- /dev/null
@@ -0,0 +1,223 @@
+/* ========================================================================== */
+/* === UMF_get_memory ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Reallocate the workspace (Numeric->Memory) and shift elements downwards.
+    needunits: increase in size so that the free space is at least this many
+    Units (to which the tuple lengths is added).
+
+    Return TRUE if successful, FALSE if out of memory.
+*/
+
+#include "umf_internal.h"
+#include "umf_garbage_collection.h"
+#include "umf_tuple_lengths.h"
+#include "umf_build_tuples.h"
+#include "umf_mem_free_tail_block.h"
+#include "umf_realloc.h"
+
+GLOBAL Int UMF_get_memory
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    Int needunits,
+    Int r2,            /* compact current front to r2-by-c2 */
+    Int c2,
+    Int do_Fcpos
+)
+{
+    Int i, minsize, newsize, newmem, costly, row, col, *Row_tlen, *Col_tlen,
+       n_row, n_col, *Row_degree, *Col_degree ;
+    Unit *mnew, *p ;
+    double nsize, bsize, tsize ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get and check parameters */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    DEBUG1 (("::::GET MEMORY::::\n")) ;
+    UMF_dump_memory (Numeric) ;
+#endif
+
+    n_row = Work->n_row ;
+    n_col = Work->n_col ;
+    Row_degree = Numeric->Rperm ;      /* for NON_PIVOTAL_ROW macro */
+    Col_degree = Numeric->Cperm ;      /* for NON_PIVOTAL_COL macro */
+    Row_tlen   = Numeric->Uilen ;
+    Col_tlen   = Numeric->Lilen ;
+
+    /* ---------------------------------------------------------------------- */
+    /* initialize the tuple list lengths */
+    /* ---------------------------------------------------------------------- */
+
+    for (row = 0 ; row < n_row ; row++)
+    {
+       if (NON_PIVOTAL_ROW (row))
+       {
+           Row_tlen [row] = 0 ;
+       }
+    }
+    for (col = 0 ; col < n_col ; col++)
+    {
+       if (NON_PIVOTAL_COL (col))
+       {
+           Col_tlen [col] = 0 ;
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* determine how much memory is needed for the tuples */
+    /* ---------------------------------------------------------------------- */
+
+    nsize = (double) needunits + 2 ;
+    needunits += UMF_tuple_lengths (Numeric, Work, &tsize) ;
+    nsize += tsize ;
+    needunits += 2 ;   /* add 2, so that newmem >= 2 is true if realloc'd */
+
+    /* note: Col_tlen and Row_tlen are updated, but the tuple lists */
+    /* themselves are not.  Do not attempt to scan the tuple lists. */
+    /* They are now stale, and are about to be destroyed and recreated. */
+
+    /* ---------------------------------------------------------------------- */
+    /* determine the desired new size of memory */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG0 (("UMF_get_memory: needunits: "ID"\n", needunits)) ;
+
+    minsize = Numeric->size + needunits ;
+    nsize += (double) Numeric->size ;
+
+    bsize = ((double) Int_MAX) / sizeof (Unit) - 1 ;
+
+    newsize = (Int) (UMF_REALLOC_INCREASE * ((double) minsize)) ;
+    nsize *= UMF_REALLOC_INCREASE ;
+    nsize += 1 ;
+
+    if (newsize < 0 || nsize > bsize)
+    {
+       /* :: realloc Numeric->Memory int overflow :: */
+       DEBUGm3 (("Realloc hit integer limit\n")) ;
+       newsize = (Int) bsize ; /* we cannot increase the size beyond bsize */
+    }
+    else
+    {
+       ASSERT (newsize <= nsize) ;
+       newsize = MAX (newsize, minsize) ;
+    }
+    newsize = MAX (newsize, Numeric->size) ;
+
+    DEBUG0 ((
+    "REALLOC MEMORY: needunits "ID" old size: "ID" new size: "ID" Units \n",
+       needunits, Numeric->size, newsize)) ;
+
+    /* Forget where the biggest free block is (we no longer need it) */
+    /* since garbage collection will occur shortly. */
+    Numeric->ibig = EMPTY ;
+
+    DEBUG0 (("Before realloc E [0] "ID"\n", Work->E [0])) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* reallocate the memory, if possible, and make it bigger */
+    /* ---------------------------------------------------------------------- */
+
+    mnew = (Unit *) NULL ;
+    while (!mnew)
+    {
+       mnew = (Unit *) UMF_realloc (Numeric->Memory, newsize, sizeof (Unit)) ;
+       if (!mnew)
+       {
+           if (newsize == minsize)     /* last realloc attempt failed */
+           {
+               /* We failed to get the minimum.  Just stick with the */
+               /* current allocation and hope that garbage collection */
+               /* can recover enough space. */
+               mnew = Numeric->Memory ;        /* no new memory available */
+               newsize = Numeric->size ;
+           }
+           else
+           {
+               /* otherwise, reduce the request and keep trying */
+               newsize = (Int) (UMF_REALLOC_REDUCTION * ((double) newsize)) ;
+               newsize = MAX (minsize, newsize) ;
+           }
+       }
+    }
+    ASSERT (mnew != (Unit *) NULL) ;
+
+    /* see if realloc had to copy, rather than just extend memory */
+    costly = (mnew != Numeric->Memory) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* extend the tail portion of memory downwards */
+    /* ---------------------------------------------------------------------- */
+
+    Numeric->Memory = mnew ;
+    if (Work->E [0])
+    {
+       Int nb, dr, dc ;
+       nb = Work->nb ;
+       dr = Work->fnr_curr ;
+       dc = Work->fnc_curr ;
+       Work->Flublock = (Entry *) (Numeric->Memory + Work->E [0]) ;
+       Work->Flblock  = Work->Flublock + nb * nb ;
+       Work->Fublock  = Work->Flblock  + dr * nb ;
+       Work->Fcblock  = Work->Fublock  + nb * dc ;
+       DEBUG0 (("after realloc E [0] "ID"\n", Work->E [0])) ;
+    }
+    ASSERT (IMPLIES (!(Work->E [0]), Work->Flublock == (Entry *) NULL)) ;
+
+    newmem = newsize - Numeric->size ;
+    ASSERT (newmem == 0 || newmem >= 2) ;
+
+    if (newmem >= 2)
+    {
+       /* reallocation succeeded */
+
+       /* point to the old tail marker block of size 1 + header */
+       p = Numeric->Memory + Numeric->size - 2 ;
+
+       /* create a new block out of the newly extended memory */
+       p->header.size = newmem - 1 ;
+       i = Numeric->size - 1 ;
+       p += newmem ;
+
+       /* create a new tail marker block */
+       p->header.prevsize = newmem - 1 ;
+       p->header.size = 1 ;
+
+       Numeric->size = newsize ;
+
+       /* free the new block */
+       UMF_mem_free_tail_block (Numeric, i) ;
+
+       Numeric->nrealloc++ ;
+
+       if (costly)
+       {
+           Numeric->ncostly++ ;
+       }
+
+    }
+    DEBUG1 (("Done with realloc memory\n")) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* garbage collection on the tail of Numeric->memory (destroys tuples) */
+    /* ---------------------------------------------------------------------- */
+
+    UMF_garbage_collection (Numeric, Work, r2, c2, do_Fcpos) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* rebuild the tuples */
+    /* ---------------------------------------------------------------------- */
+
+    return (UMF_build_tuples (Numeric, Work)) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_get_memory.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_get_memory.h
new file mode 100644 (file)
index 0000000..754f1fa
--- /dev/null
@@ -0,0 +1,16 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_get_memory
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    Int needunits,
+    Int r2,
+    Int c2,
+    Int do_Fcpos
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_grow_front.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_grow_front.c
new file mode 100644 (file)
index 0000000..9ecf673
--- /dev/null
@@ -0,0 +1,295 @@
+/* ========================================================================== */
+/* === UMF_grow_front ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* Current frontal matrix is too small.  Make it bigger. */
+
+#include "umf_internal.h"
+#include "umf_realloc.h"
+#include "umf_mem_free_tail_block.h"
+#include "umf_mem_alloc_tail_block.h"
+#include "umf_get_memory.h"
+
+GLOBAL Int UMF_grow_front
+(
+    NumericType *Numeric,
+    Int fnr2,          /* desired size is fnr2-by-fnc2 */
+    Int fnc2,
+    WorkType *Work,
+    Int do_what                /* -1: UMF_start_front
+                        * 0:  UMF_init_front, do not recompute Fcpos
+                        * 1:  UMF_extend_front
+                        * 2:  UMF_init_front, recompute Fcpos */
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Entry *Fcold, *Fcnew ;
+    Int j, i, col, *Fcpos, *Fcols, fnrows_max, fncols_max, fnr_curr, nb,
+       fnrows_new, fncols_new, fnr_min, fnc_min, minsize,
+       newsize, fnrows, fncols, *E, eloc ;
+    double s ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    if (do_what != -1) UMF_debug++ ;
+    DEBUG0 (("\n\n====================GROW FRONT: do_what: "ID"\n", do_what)) ;
+    if (do_what != -1) UMF_debug-- ;
+    ASSERT (Work->do_grow) ;
+    ASSERT (Work->fnpiv == 0) ;
+#endif
+
+    Fcols = Work->Fcols ;
+    Fcpos = Work->Fcpos ;
+    E = Work->E ;
+
+    /* ---------------------------------------------------------------------- */
+    /* The current front is too small, find the new size */
+    /* ---------------------------------------------------------------------- */
+
+    /* maximum size of frontal matrix for this chain */
+    nb = Work->nb ;
+    fnrows_max = Work->fnrows_max + nb ;
+    fncols_max = Work->fncols_max + nb ;
+    ASSERT (fnrows_max >= 0 && (fnrows_max % 2) == 1) ;
+    DEBUG0 (("Max     size: "ID"-by-"ID" (incl. "ID" pivot block\n",
+       fnrows_max, fncols_max, nb)) ;
+
+    /* current dimensions of frontal matrix: fnr-by-fnc */
+    DEBUG0 (("Current : "ID"-by-"ID" (excl "ID" pivot blocks)\n",
+               Work->fnr_curr, Work->fnc_curr, nb)) ;
+    ASSERT (Work->fnr_curr >= 0) ;
+    ASSERT ((Work->fnr_curr % 2 == 1) || Work->fnr_curr == 0) ;
+
+    /* required dimensions of frontal matrix: fnr_min-by-fnc_min */
+    fnrows_new = Work->fnrows_new + 1 ;
+    fncols_new = Work->fncols_new + 1 ;
+    ASSERT (fnrows_new >= 0) ;
+    if (fnrows_new % 2 == 0) fnrows_new++ ;
+    fnrows_new += nb ;
+    fncols_new += nb ;
+    fnr_min = MIN (fnrows_new, fnrows_max) ;
+    fnc_min = MIN (fncols_new, fncols_max) ;
+    minsize = fnr_min * fnc_min ;
+    if (INT_OVERFLOW ((double) fnr_min * (double) fnc_min * sizeof (Entry)))
+    {
+       /* :: the minimum front size is bigger than the integer maximum :: */
+       return (FALSE) ;
+    }
+    ASSERT (fnr_min >= 0) ;
+    ASSERT (fnr_min % 2 == 1) ;
+
+    DEBUG0 (("Min     : "ID"-by-"ID"\n", fnr_min, fnc_min)) ;
+
+    /* grow the front to fnr2-by-fnc2, but no bigger than the maximum,
+     * and no smaller than the minumum. */
+    DEBUG0 (("Desired : ("ID"+"ID")-by-("ID"+"ID")\n", fnr2, nb, fnc2, nb)) ;
+    fnr2 += nb ;
+    fnc2 += nb ;
+    ASSERT (fnr2 >= 0) ;
+    if (fnr2 % 2 == 0) fnr2++ ;
+    fnr2 = MAX (fnr2, fnr_min) ;
+    fnc2 = MAX (fnc2, fnc_min) ;
+    fnr2 = MIN (fnr2, fnrows_max) ;
+    fnc2 = MIN (fnc2, fncols_max) ;
+    DEBUG0 (("Try     : "ID"-by-"ID"\n", fnr2, fnc2)) ;
+    ASSERT (fnr2 >= 0) ;
+    ASSERT (fnr2 % 2 == 1) ;
+
+    s = ((double) fnr2) * ((double) fnc2) ;
+    if (INT_OVERFLOW (s * sizeof (Entry)))
+    {
+       /* :: frontal matrix size int overflow :: */
+       /* the desired front size is bigger than the integer maximum */
+       /* compute a such that a*a*s < Int_MAX / sizeof (Entry) */
+       double a = 0.9 * sqrt ((Int_MAX / sizeof (Entry)) / s) ;
+       fnr2 = MAX (fnr_min, a * fnr2) ;
+       fnc2 = MAX (fnc_min, a * fnc2) ;
+       /* the new frontal size is a*r*a*c = a*a*s */
+       newsize = fnr2 * fnc2 ;
+       ASSERT (fnr2 >= 0) ;
+       if (fnr2 % 2 == 0) fnr2++ ;
+       fnc2 = newsize / fnr2 ;
+    }
+
+    fnr2 = MAX (fnr2, fnr_min) ;
+    fnc2 = MAX (fnc2, fnc_min) ;
+    newsize = fnr2 * fnc2 ;
+
+    ASSERT (fnr2 >= 0) ;
+    ASSERT (fnr2 % 2 == 1) ;
+    ASSERT (fnr2 >= fnr_min) ;
+    ASSERT (fnc2 >= fnc_min) ;
+    ASSERT (newsize >= minsize) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* free the current front if it is empty of any numerical values */
+    /* ---------------------------------------------------------------------- */
+
+    if (E [0] && do_what != 1)
+    {
+       /* free the current front, if it exists and has nothing in it */
+       DEBUG0 (("Freeing empty front\n")) ;
+       UMF_mem_free_tail_block (Numeric, E [0]) ;
+       E [0] = 0 ;
+       Work->Flublock = (Entry *) NULL ;
+       Work->Flblock  = (Entry *) NULL ;
+       Work->Fublock  = (Entry *) NULL ;
+       Work->Fcblock  = (Entry *) NULL ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the new front, doing garbage collection if necessary */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    UMF_allocfail = FALSE ;
+    if (UMF_gprob > 0)  /* a double relop, but ignore NaN case */
+    {
+       double rrr = ((double) (rand ( ))) / (((double) RAND_MAX) + 1) ;
+       DEBUG1 (("Check random %e %e\n", rrr, UMF_gprob)) ;
+       UMF_allocfail = rrr < UMF_gprob ;
+       if (UMF_allocfail) DEBUGm2 (("Random garbage collection (grow)\n")) ;
+    }
+#endif
+
+    DEBUG0 (("Attempt size: "ID"-by-"ID"\n", fnr2, fnc2)) ;
+    eloc = UMF_mem_alloc_tail_block (Numeric, UNITS (Entry, newsize)) ;
+
+    if (!eloc)
+    {
+       /* Do garbage collection, realloc, and try again. Compact the current
+        * contribution block in the front to fnrows-by-fncols.  Note that
+        * there are no pivot rows/columns in current front.  Do not recompute
+        * Fcpos in UMF_garbage_collection. */
+       DEBUGm3 (("get_memory from umf_grow_front\n")) ;
+       if (!UMF_get_memory (Numeric, Work, 1 + UNITS (Entry, newsize),
+           Work->fnrows, Work->fncols, FALSE))
+       {
+           /* :: out of memory in umf_grow_front :: */
+           return (FALSE) ;    /* out of memory */
+       }
+       DEBUG0 (("Attempt size: "ID"-by-"ID" again\n", fnr2, fnc2)) ;
+       eloc = UMF_mem_alloc_tail_block (Numeric, UNITS (Entry, newsize)) ;
+    }
+
+    /* try again with something smaller */
+    while ((fnr2 != fnr_min || fnc2 != fnc_min) && !eloc)
+    {
+       fnr2 = MIN (fnr2 - 2, fnr2 * UMF_REALLOC_REDUCTION) ;
+       fnc2 = MIN (fnc2 - 2, fnc2 * UMF_REALLOC_REDUCTION) ;
+       ASSERT (fnr_min >= 0) ;
+       ASSERT (fnr_min % 2 == 1) ;
+       fnr2 = MAX (fnr_min, fnr2) ;
+       fnc2 = MAX (fnc_min, fnc2) ;
+       ASSERT (fnr2 >= 0) ;
+       if (fnr2 % 2 == 0) fnr2++ ;
+       newsize = fnr2 * fnc2 ;
+       DEBUGm3 (("Attempt smaller size: "ID"-by-"ID" minsize "ID"-by-"ID"\n",
+           fnr2, fnc2, fnr_min, fnc_min)) ;
+       eloc = UMF_mem_alloc_tail_block (Numeric, UNITS (Entry, newsize)) ;
+    }
+
+    /* try again with the smallest possible size */
+    if (!eloc)
+    {
+       fnr2 = fnr_min ;
+       fnc2 = fnc_min ;
+       newsize = minsize ;
+       DEBUG0 (("Attempt minsize: "ID"-by-"ID"\n", fnr2, fnc2)) ;
+       eloc = UMF_mem_alloc_tail_block (Numeric, UNITS (Entry, newsize)) ;
+    }
+
+    if (!eloc)
+    {
+       /* out of memory */
+       return (FALSE) ;
+    }
+
+    ASSERT (fnr2 >= 0) ;
+    ASSERT (fnr2 % 2 == 1) ;
+    ASSERT (fnr2 >= fnr_min && fnc2 >= fnc_min) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* copy the old frontal matrix into the new one */
+    /* ---------------------------------------------------------------------- */
+
+    /* old contribution block (if any) */
+    fnr_curr = Work->fnr_curr ;            /* garbage collection can change fn*_curr */
+    ASSERT (fnr_curr >= 0) ;
+    ASSERT ((fnr_curr % 2 == 1) || fnr_curr == 0) ;
+    fnrows = Work->fnrows ;
+    fncols = Work->fncols ;
+    Fcold = Work->Fcblock ;
+
+    /* remove nb from the sizes */
+    fnr2 -= nb ;
+    fnc2 -= nb ;
+
+    /* new frontal matrix */
+    Work->Flublock = (Entry *) (Numeric->Memory + eloc) ;
+    Work->Flblock  = Work->Flublock + nb * nb ;
+    Work->Fublock  = Work->Flblock  + nb * fnr2 ;
+    Work->Fcblock  = Work->Fublock  + nb * fnc2 ;
+    Fcnew = Work->Fcblock ;
+
+    if (E [0])
+    {
+       /* copy the old contribution block into the new one */
+       for (j = 0 ; j < fncols ; j++)
+       {
+           col = Fcols [j] ;
+           DEBUG1 (("copy col "ID" \n",col)) ;
+           ASSERT (col >= 0 && col < Work->n_col) ;
+           for (i = 0 ; i < fnrows ; i++)
+           {
+               Fcnew [i] = Fcold [i] ;
+           }
+           Fcnew += fnr2 ;
+           Fcold += fnr_curr ;
+           DEBUG1 (("new offset col "ID" "ID"\n",col, j * fnr2)) ;
+           Fcpos [col] = j * fnr2 ;
+       }
+    }
+    else if (do_what == 2)
+    {
+       /* just find the new column offsets */
+       for (j = 0 ; j < fncols ; j++)
+       {
+           col = Fcols [j] ;
+           DEBUG1 (("new offset col "ID" "ID"\n",col, j * fnr2)) ;
+           Fcpos [col] = j * fnr2 ;
+       }
+    }
+
+    /* free the old frontal matrix */
+    UMF_mem_free_tail_block (Numeric, E [0]) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* new frontal matrix size */
+    /* ---------------------------------------------------------------------- */
+
+    E [0] = eloc ;
+    Work->fnr_curr = fnr2 ;        /* C block is fnr2-by-fnc2 */
+    Work->fnc_curr = fnc2 ;
+    Work->fcurr_size = newsize ;    /* including LU, L, U, and C blocks */
+    Work->do_grow = FALSE ;        /* the front has just been grown */
+
+    ASSERT (Work->fnr_curr >= 0) ;
+    ASSERT (Work->fnr_curr % 2 == 1) ;
+    DEBUG0 (("Newly grown front: "ID"+"ID" by "ID"+"ID"\n", Work->fnr_curr,
+       nb, Work->fnc_curr, nb)) ;
+    return (TRUE) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_grow_front.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_grow_front.h
new file mode 100644 (file)
index 0000000..2f27fe5
--- /dev/null
@@ -0,0 +1,15 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_grow_front
+(
+    NumericType *Numeric,
+    Int fnr2,
+    Int fnc2,
+    WorkType *Work,
+    Int do_what
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_init_front.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_init_front.c
new file mode 100644 (file)
index 0000000..cce2dd1
--- /dev/null
@@ -0,0 +1,268 @@
+/* ========================================================================== */
+/* === UMF_init_front ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+#include "umf_internal.h"
+#include "umf_grow_front.h"
+
+/* ========================================================================== */
+/* === zero_init_front ====================================================== */
+/* ========================================================================== */
+
+/* Set the initial frontal matrix to zero. */
+
+PRIVATE void zero_init_front (Int m, Int n, Entry *Fcblock, Int d)
+{
+    Int i, j ;
+    Entry *F, *Fj = Fcblock ;
+    for (j = 0 ; j < m ; j++)
+    {
+       F = Fj ;
+       Fj += d ;
+       for (i = 0 ; i < n ; i++)
+       {
+           /* CLEAR (Fcblock [i + j*d]) ; */
+           CLEAR (*F) ;
+           F++ ;
+       }
+    }
+}
+
+/* ========================================================================== */
+/* === UMF_init_front ======================================================= */
+/* ========================================================================== */
+
+GLOBAL Int UMF_init_front
+(
+    NumericType *Numeric,
+    WorkType *Work
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int i, j, fnr_curr, row, col, *Frows, *Fcols,
+       *Fcpos, *Frpos, fncols, fnrows, *Wrow, fnr2, fnc2, rrdeg, ccdeg, *Wm,
+       fnrows_extended ;
+    Entry *Fcblock, *Fl, *Wy, *Wx ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get current frontal matrix and check for frontal growth */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    DEBUG0 (("INIT FRONT\n")) ;
+    DEBUG1 (("CURR before init:\n")) ;
+    UMF_dump_current_front (Numeric, Work, FALSE) ;
+#endif
+    if (Work->do_grow)
+    {
+       fnr2 = UMF_FRONTAL_GROWTH * Work->fnrows_new + 2 ;
+       fnc2 = UMF_FRONTAL_GROWTH * Work->fncols_new + 2 ;
+       if (!UMF_grow_front (Numeric, fnr2, fnc2, Work,
+           Work->pivrow_in_front ? 2 : 0))
+       {
+           /* :: out of memory in umf_init_front :: */
+           DEBUGm4 (("out of memory: init front\n")) ;
+           return (FALSE) ;
+       }
+    }
+#ifndef NDEBUG
+    DEBUG1 (("CURR after grow:\n")) ;
+    UMF_dump_current_front (Numeric, Work, FALSE) ;
+    DEBUG1 (("fnrows new "ID" fncols new "ID"\n",
+       Work->fnrows_new, Work->fncols_new)) ;
+#endif
+    ASSERT (Work->fnpiv == 0) ;
+    fnr_curr = Work->fnr_curr ;
+    ASSERT (Work->fnrows_new + 1 <= fnr_curr) ;
+    ASSERT (Work->fncols_new + 1 <= Work->fnc_curr) ;
+    ASSERT (fnr_curr >= 0) ;
+    ASSERT (fnr_curr % 2 == 1) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    /* current front is defined by pivot row and column */
+
+    Frows = Work->Frows ;
+    Fcols = Work->Fcols ;
+    Frpos = Work->Frpos ;
+    Fcpos = Work->Fcpos ;
+
+    Work->fnzeros = 0 ;
+
+    ccdeg = Work->ccdeg ;
+    rrdeg = Work->rrdeg ;
+
+    fnrows = Work->fnrows ;
+    fncols = Work->fncols ;
+
+    /* if both pivrow and pivcol are in front, then we extend the old one */
+    /* in UMF_extend_front, rather than starting a new one here. */
+    ASSERT (! (Work->pivrow_in_front && Work->pivcol_in_front)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* place pivot column pattern in frontal matrix */
+    /* ---------------------------------------------------------------------- */
+
+    Fl = Work->Flblock ;
+
+    if (Work->pivcol_in_front)
+    {
+       /* Append the pivot column extension.
+        * Note that all we need to do is increment the size, since the
+        * candidate pivot column pattern is already in place in
+        * Frows [0 ... fnrows-1] (the old pattern), and
+        * Frows [fnrows ... fnrows + Work->ccdeg - 1] (the new
+        * pattern).  Frpos is also properly defined. */
+       /* make a list of the new rows to scan */
+       Work->fscan_row = fnrows ;      /* only scan the new rows */
+       Work->NewRows = Work->Wrp ;
+       Wy = Work->Wy ;
+       for (i = 0 ; i < fnrows ; i++)
+       {
+           Fl [i] = Wy [i] ;
+       }
+       fnrows_extended = fnrows + ccdeg ;
+       for (i = fnrows ; i < fnrows_extended ; i++)
+       {
+           Fl [i] = Wy [i] ;
+           /* flip the row index, since Wrp must be < 0 */
+           row = Frows [i] ;
+           Work->NewRows [i] = FLIP (row) ;
+       }
+       fnrows = fnrows_extended ;
+    }
+    else
+    {
+       /* this is a completely new column */
+       Work->fscan_row = 0 ;                   /* scan all the rows */
+       Work->NewRows = Frows ;
+       Wm = Work->Wm ;
+       Wx = Work->Wx ;
+       for (i = 0 ; i < ccdeg ; i++)
+       {
+           Fl [i] = Wx [i] ;
+           row = Wm [i] ;
+           Frows [i] = row ;
+           Frpos [row] = i ;
+       }
+       fnrows = ccdeg ;
+    }
+
+    Work->fnrows = fnrows ;
+
+#ifndef NDEBUG
+    DEBUG3 (("New Pivot col "ID" now in front, length "ID"\n",
+       Work->pivcol, fnrows)) ;
+    for (i = 0 ; i < fnrows ; i++)
+    {
+       DEBUG4 ((" "ID": row "ID"\n", i, Frows [i])) ;
+       ASSERT (Frpos [Frows [i]] == i) ;
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* place pivot row pattern in frontal matrix */
+    /* ---------------------------------------------------------------------- */
+
+    Wrow = Work->Wrow ;
+    if (Work->pivrow_in_front)
+    {
+       /* append the pivot row extension */
+       Work->fscan_col = fncols ;      /* only scan the new columns */
+       Work->NewCols = Work->Wp ;
+#ifndef NDEBUG
+       for (j = 0 ; j < fncols ; j++)
+       {
+           col = Fcols [j] ;
+           ASSERT (col >= 0 && col < Work->n_col) ;
+           ASSERT (Fcpos [col] == j * fnr_curr) ;
+       }
+#endif
+       /* Wrow == Fcol for the IN_IN case, and for the OUT_IN case when
+        * the pivrow [IN][IN] happens to be the same as pivrow [OUT][IN].
+        * See UMF_local_search for more details. */
+       ASSERT (IMPLIES (Work->pivcol_in_front, Wrow == Fcols)) ;
+       if (Wrow == Fcols)
+       {
+           for (j = fncols ; j < rrdeg ; j++)
+           {
+               col = Wrow [j] ;
+               /* Fcols [j] = col ; not needed */
+               /* flip the col index, since Wp must be < 0 */
+               Work->NewCols [j] = FLIP (col) ;
+               Fcpos [col] = j * fnr_curr ;
+           }
+       }
+       else
+       {
+           for (j = fncols ; j < rrdeg ; j++)
+           {
+               col = Wrow [j] ;
+               Fcols [j] = col ;
+               /* flip the col index, since Wp must be < 0 */
+               Work->NewCols [j] = FLIP (col) ;
+               Fcpos [col] = j * fnr_curr ;
+           }
+       }
+    }
+    else
+    {
+       /* this is a completely new row */
+       Work->fscan_col = 0 ;                   /* scan all the columns */
+       Work->NewCols = Fcols ;
+       for (j = 0 ; j < rrdeg ; j++)
+       {
+           col = Wrow [j] ;
+           Fcols [j] = col ;
+           Fcpos [col] = j * fnr_curr ;
+       }
+    }
+
+    DEBUGm1 (("rrdeg "ID" fncols "ID"\n", rrdeg, fncols)) ;
+    fncols = rrdeg ;
+    Work->fncols = fncols ;
+
+    /* ---------------------------------------------------------------------- */
+    /* clear the frontal matrix */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (fnrows == Work->fnrows_new + 1) ;
+    ASSERT (fncols == Work->fncols_new + 1) ;
+
+    Fcblock = Work->Fcblock ;
+    ASSERT (Fcblock != (Entry *) NULL) ;
+
+    zero_init_front (fncols, fnrows, Fcblock, fnr_curr) ;
+
+#ifndef NDEBUG
+    DEBUG3 (("New Pivot row "ID" now in front, length "ID" fnr_curr "ID"\n",
+               Work->pivrow, fncols, fnr_curr)) ;
+    for (j = 0 ; j < fncols ; j++)
+    {
+       DEBUG4 (("col "ID" position "ID"\n", j, Fcols [j])) ;
+       ASSERT (Fcpos [Fcols [j]] == j * fnr_curr) ;
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* current workspace usage: */
+    /* ---------------------------------------------------------------------- */
+
+    /* Fcblock [0..fnr_curr-1, 0..fnc_curr-1]: space for the new frontal
+     * matrix.  Fcblock (i,j) is located at Fcblock [i+j*fnr_curr] */
+
+    return (TRUE) ;
+
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_init_front.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_init_front.h
new file mode 100644 (file)
index 0000000..96a77ab
--- /dev/null
@@ -0,0 +1,12 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_init_front
+(
+    NumericType *Numeric,
+    WorkType *Work
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_internal.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_internal.h
new file mode 100644 (file)
index 0000000..f4e26c2
--- /dev/null
@@ -0,0 +1,756 @@
+/* ========================================================================== */
+/* === umf_internal.h ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    This file is for internal use in UMFPACK itself, and should not be included
+    in user code.  Use umfpack.h instead.  User-accessible file names and
+    routine names all start with the letters "umfpack_".  Non-user-accessible
+    file names and routine names all start with "umf_".
+*/
+
+/* -------------------------------------------------------------------------- */
+/* ANSI standard include files */
+/* -------------------------------------------------------------------------- */
+
+/* from float.h:  DBL_EPSILON */
+#include <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) || defined (_win32) || defined (__win32) || defined (WIN32)
+#define UMF_WINDOWS
+#define UMFPACK_ARCHITECTURE "Microsoft Windows"
+
+#elif defined (__hppa) || defined (__hpux) || defined (MHPUX) || defined (ARCH_HPUX)
+#define UMF_HP
+#define UMFPACK_ARCHITECTURE "HP Unix"
+
+#elif defined (__hp700) || defined (MHP700) || defined (ARCH_HP700)
+#define UMF_HP
+#define UMFPACK_ARCHITECTURE "HP 700 Unix"
+
+#else
+/* If the architecture is unknown, and you call the BLAS, you may need to */
+/* define BLAS_BY_VALUE, BLAS_NO_UNDERSCORE, and/or BLAS_CHAR_ARG yourself. */
+#define UMFPACK_ARCHITECTURE "unknown"
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+/* basic definitions (see also amd_internal.h) */
+/* -------------------------------------------------------------------------- */
+
+#define ONES_COMPLEMENT(r) (-(r)-1)
+
+/* -------------------------------------------------------------------------- */
+/* AMD include file */
+/* -------------------------------------------------------------------------- */
+
+/* stdio.h, stdlib.h, limits.h, and math.h, NDEBUG definition,
+ * assert.h, and MATLAB include files */
+#include "amd_internal.h"
+
+/* -------------------------------------------------------------------------- */
+/* Real/complex and int/long definitions, double relops */
+/* -------------------------------------------------------------------------- */
+
+#include "umf_version.h"
+
+/* -------------------------------------------------------------------------- */
+/* Compile-time configurations */
+/* -------------------------------------------------------------------------- */
+
+#include "umf_config.h"
+
+/* -------------------------------------------------------------------------- */
+/* umfpack include file */
+/* -------------------------------------------------------------------------- */
+
+#include "umfpack.h"
+
+/* -------------------------------------------------------------------------- */
+/* for contents of Info.  This must correlate with umfpack.h */
+/* -------------------------------------------------------------------------- */
+
+#define ESTIMATE (UMFPACK_NUMERIC_SIZE_ESTIMATE - UMFPACK_NUMERIC_SIZE)
+#define ACTUAL 0
+
+/* -------------------------------------------------------------------------- */
+/* get a parameter from the Control array */
+/* -------------------------------------------------------------------------- */
+
+#define GET_CONTROL(i,default) \
+    ((Control != (double *) NULL) ? \
+       (SCALAR_IS_NAN (Control [i]) ? default : Control [i]) \
+       : default)
+
+/* -------------------------------------------------------------------------- */
+/* for clearing the external degree counters */
+/* -------------------------------------------------------------------------- */
+
+#define MAX_MARK(n) Int_MAX - (2*(n)+1)
+
+/* -------------------------------------------------------------------------- */
+/* convert number of Units to MBytes */
+/* -------------------------------------------------------------------------- */
+
+#define MBYTES(units) (((units) * sizeof (Unit)) / 1048576.0)
+
+/* -------------------------------------------------------------------------- */
+/* dense row/column macro */
+/* -------------------------------------------------------------------------- */
+
+/* In order for a row or column to be treated as "dense", it must have more */
+/* entries than the value returned by this macro.  n is the dimension of the */
+/* matrix, and alpha is the dense row/column control parameter. */
+
+/* Note: this is not defined if alpha is NaN or Inf: */
+#define UMFPACK_DENSE_DEGREE_THRESHOLD(alpha,n) \
+    ((Int) MAX (16.0, (alpha) * 16.0 * sqrt ((double) (n))))
+
+/* -------------------------------------------------------------------------- */
+/* PRINTF */
+/* -------------------------------------------------------------------------- */
+
+#define PRINTFk(k,params) { if (prl >= (k)) { PRINTF (params) ; } }
+#define PRINTF1(params) PRINTFk (1, params)
+#define PRINTF2(params) PRINTFk (2, params)
+#define PRINTF3(params) PRINTFk (3, params)
+#define PRINTF4(params) PRINTFk (4, params)
+#define PRINTF5(params) PRINTFk (5, params)
+#define PRINTF6(params) PRINTFk (6, params)
+
+/* -------------------------------------------------------------------------- */
+/* Fixed control parameters */
+/* -------------------------------------------------------------------------- */
+
+/* maximum number of columns to consider at one time, in a single front */
+#define MAX_CANDIDATES 128
+
+/* reduce Numeric->Memory request by this ratio, if allocation fails */
+#define UMF_REALLOC_REDUCTION (0.95)
+
+/* increase Numeric->Memory request by this ratio, if we need more */
+#define UMF_REALLOC_INCREASE (1.2)
+
+/* increase the dimensions of the current frontal matrix by this factor
+ * when it needs to grow. */
+#define UMF_FRONTAL_GROWTH (1.2)
+
+/* largest BLAS block size permitted */
+#define MAXNB 64
+
+/* if abs (y) < RECIPROCAL_TOLERANCE, then compute x/y.  Otherwise x*(1/y).
+ * Ignored if NRECIPROCAL is defined */
+#define RECIPROCAL_TOLERANCE 1e-12
+
+/* -------------------------------------------------------------------------- */
+/* Memory allocator */
+/* -------------------------------------------------------------------------- */
+
+/* The MATLAB mexFunction uses MATLAB's memory manager, while the C-callable
+ * AMD library uses the ANSI C malloc, free, and realloc routines.  To use
+ * the mx* memory allocation routines, use -DNUTIL when compiling.
+ */
+
+#undef ALLOCATE
+#undef FREE
+#undef REALLOC
+
+#ifdef MATLAB_MEX_FILE
+
+#ifdef NUTIL
+
+/* These functions simply terminate the mexFunction if they fail to allocate
+ * memory.  That's too restrictive for UMFPACK. */
+#define ALLOCATE mxMalloc
+#define FREE mxFree
+#define REALLOCATE mxRealloc
+
+#else
+
+/* Use internal MATLAB memory allocation routines, used by built-in MATLAB
+ * functions.  These are not documented, but are available for use.  Their
+ * prototypes are in util.h, but that file is not provided to the MATLAB user.
+ * The advantage of using these routines is that they return NULL if out of
+ * memory, instead of terminating the mexFunction.  UMFPACK attempts to allocate
+ * extra space for "elbow room", and then reduces its request if the memory is
+ * not available.  That strategy doesn't work with the mx* routines.
+ */
+void *utMalloc (size_t size) ;
+void utFree (void *p) ;
+void *utRealloc (void *p, size_t size) ;
+#define ALLOCATE utMalloc
+#define FREE utFree
+#define REALLOCATE utRealloc
+
+#endif
+#else
+#ifdef MATHWORKS
+
+/* Compiling as a built-in routine.  Since out-of-memory conditions are checked
+ * after every allocation, we can use ut* routines here. */
+#define ALLOCATE utMalloc
+#define FREE utFree
+#define REALLOCATE utRealloc
+
+#else
+
+/* use the ANSI C memory allocation routines */
+#define ALLOCATE malloc
+#define FREE free
+#define REALLOCATE realloc
+
+#endif
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* Memory space definitions */
+/* -------------------------------------------------------------------------- */
+
+/* for memory alignment - assume double has worst case alignment */
+typedef double Align ;
+
+/* get number of bytes required to hold n items of a type: */
+/* note that this will not overflow, because sizeof (type) is always */
+/* greater than or equal to sizeof (Int) >= 2 */
+#define BYTES(type,n) (sizeof (type) * (n))
+
+/* ceiling of (b/u).  Assumes b >= 0 and u > 0 */
+#define CEILING(b,u) (((b) + (u) - 1) / (u))
+
+/* get number of Units required to hold n items of a type: */
+#define UNITS(type,n) (CEILING (BYTES (type, n), sizeof (Unit)))
+
+/* same as DUNITS, but use double instead of int to avoid overflow */
+#define DUNITS(type,n) (ceil (BYTES (type, (double) n) / sizeof (Unit)))
+
+union Unit_union
+{      /* memory is allocated in multiples of Unit */
+    struct
+    {
+       Int
+           size,       /* size, in Units, of the block, excl. header block */
+                       /* size >= 0: block is in use */
+                       /* size < 0: block is free, of |size| Units */
+           prevsize ;  /* size, in Units, of preceding block in S->Memory */
+                       /* during garbage_collection, prevsize is set to -e-1 */
+                       /* for element e, or positive (and thus a free block) */
+                       /* otherwise */
+    } header ;         /* block header */
+    Align  xxxxxx ;    /* force alignment of blocks (xxxxxx is never used) */
+} ;
+
+typedef union Unit_union Unit ;
+
+/* get the size of an allocated block */
+#define GET_BLOCK_SIZE(p) (((p)-1)->header.size)
+
+/* -------------------------------------------------------------------------- */
+/* Numeric */
+/* -------------------------------------------------------------------------- */
+
+/*
+    NUMERIC_VALID and SYMBOLIC_VALID:
+    The different values of SYBOLIC_VALID and NUMERIC_VALID are chosen as a
+    first defense against corrupted *Symbolic or *Numeric pointers passed to an
+    UMFPACK routine.  They also ensure that the objects are used only by the
+    same version that created them (umfpack_di_*, umfpack_dl_*, umfpack_zi_*,
+    or umfpack_zl_*).  The values have also been changed since prior releases of
+    the code to ensure that all routines that operate on the objects are of the
+    same release.  The values themselves are purely arbitrary.  The are less
+    than the ANSI C required minimums of INT_MAX and LONG_MAX, respectively.
+*/
+
+#ifdef DINT
+#define NUMERIC_VALID  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
+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
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_is_permutation.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_is_permutation.c
new file mode 100644 (file)
index 0000000..845ece2
--- /dev/null
@@ -0,0 +1,56 @@
+/* ========================================================================== */
+/* === UMF_is_permutation =================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* Return TRUE if P is a r-permutation vector, FALSE otherwise */
+/* P [0..r-1] must be an r-permutation of 0..n-1 */
+
+#include "umf_internal.h"
+
+GLOBAL Int UMF_is_permutation
+(
+    const Int P [ ],   /* permutation of size r */
+    Int W [ ],         /* workspace of size n */
+    Int n,
+    Int r
+)
+{
+    Int i, k ;
+
+    if (!P)
+    {
+       /* if P is (Int *) NULL, this is the identity permutation */
+       return (TRUE) ;
+    }
+
+    ASSERT (W != (Int *) NULL) ;
+
+    for (i = 0 ; i < n ; i++)
+    {
+       W [i] = FALSE ;
+    }
+    for (k = 0 ; k < r ; k++)
+    {
+       i = P [k] ;
+       DEBUG5 (("k "ID" i "ID"\n", k, i)) ;
+       if (i < 0 || i >= n)
+       {
+           DEBUG0 (("i out of range "ID" "ID"\n", i, n)) ;
+           return (FALSE) ;
+       }
+       if (W [i])
+       {
+           DEBUG0 (("i duplicate "ID"\n", i)) ;
+           return (FALSE) ;
+       }
+       W [i] = TRUE ;
+    }
+    return (TRUE) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_is_permutation.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_is_permutation.h
new file mode 100644 (file)
index 0000000..386604b
--- /dev/null
@@ -0,0 +1,14 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_is_permutation
+(
+    const Int P [ ],
+    Int W [ ],
+    Int n,
+    Int r
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel.c
new file mode 100644 (file)
index 0000000..7e433f1
--- /dev/null
@@ -0,0 +1,300 @@
+/* ========================================================================== */
+/* === UMF_kernel =========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Primary factorization routine.   Called by UMFPACK_numeric.
+    Returns:
+       UMFPACK_OK if successful,
+       UMFPACK_ERROR_out_of_memory if out of memory, or
+       UMFPACK_ERROR_different_pattern if pattern of matrix (Ap and/or Ai)
+          has changed since the call to UMFPACK_*symbolic.
+*/
+
+#include "umf_internal.h"
+#include "umf_kernel_init.h"
+#include "umf_init_front.h"
+#include "umf_start_front.h"
+#include "umf_assemble.h"
+#include "umf_scale_column.h"
+#include "umf_local_search.h"
+#include "umf_create_element.h"
+#include "umf_extend_front.h"
+#include "umf_blas3_update.h"
+#include "umf_store_lu.h"
+#include "umf_kernel_wrapup.h"
+
+/* perform an action, and return if out of memory */
+#define DO(action) { if (! (action)) { return (UMFPACK_ERROR_out_of_memory) ; }}
+
+GLOBAL Int UMF_kernel
+(
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const double Ax [ ],
+#ifdef COMPLEX
+    const double Az [ ],
+#endif
+    NumericType *Numeric,
+    WorkType *Work,
+    SymbolicType *Symbolic
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int j, f1, f2, chain, nchains, *Chain_start, status, fixQ, evaporate,
+       *Front_npivcol, jmax, nb, 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/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel.h
new file mode 100644 (file)
index 0000000..3f64436
--- /dev/null
@@ -0,0 +1,19 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_kernel
+(
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const double Ax [ ],
+#ifdef COMPLEX
+    const double Az [ ],
+#endif
+    NumericType *Numeric,
+    WorkType *Work,
+    SymbolicType *Symbolic
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel_init.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel_init.c
new file mode 100644 (file)
index 0000000..a1f0b97
--- /dev/null
@@ -0,0 +1,1053 @@
+/* ========================================================================== */
+/* === UMF_kernel_init ====================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Initialize the kernel: scale the matrix, load the initial elements, and
+    build the tuple lists.
+
+    Returns TRUE if successful, FALSE if out of memory or if the pattern has
+    changed since UMFPACK_*symbolic.  UMFPACK_numeric allocates at least enough
+    space for UMF_kernel_init to succeed; otherwise it does not call
+    UMF_kernel_init.  So an out-of-memory condition means that the pattern must
+    have gotten larger.
+*/
+
+#include "umf_internal.h"
+#include "umf_tuple_lengths.h"
+#include "umf_build_tuples.h"
+#include "umf_mem_init_memoryspace.h"
+#include "umf_mem_alloc_element.h"
+#include "umf_mem_alloc_head_block.h"
+#include "umf_mem_alloc_tail_block.h"
+#include "umf_mem_free_tail_block.h"
+#include "umf_free.h"
+#include "umf_scale.h"
+
+/* ========================================================================== */
+/* === packsp =============================================================== */
+/* ========================================================================== */
+
+/* remove zero 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, *Bx, *Bx2 ;
+    Int p, i, len, len_new, *Bi, *Bi2 ;
+    double s ;
+
+    /* get the pointers to the sparse vector, and its length */
+    p = *p_p ;
+    len = *p_len ;
+    Bi = (Int   *) (Memory + p) ; p += UNITS (Int,   len) ;
+    Bx = (Entry *) (Memory + p) ; p += UNITS (Entry, len) ;
+    DEBUGm4 (("  p "ID" len "ID" pnew "ID"\n", p, len, pnew)) ;
+
+    /* the vector resides in Bi [0..len-1] and Bx [0..len-1] */
+
+    /* first, compact the vector in place */
+    len_new = 0 ;
+    for (p = 0 ; p < len ; p++)
+    {
+       i = Bi [p] ;
+       x = Bx [p] ;
+       DEBUGm4 (("    old vector: i "ID" value: ", i)) ;
+       EDEBUGk (-4, x) ;
+       DEBUGm4 (("\n")) ;
+       ASSERT (i >= 0) ;
+       /* skip if zero 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 */
+    /* ---------------------------------------------------------------------- */
+
+    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 ;
+    double unused = 0, *Rs, rsmin, rsmax, rs, droptol ;
+    Entry *D, *C, x, *Lval, pivot_value, **Rpx ;
+    Element *ep ;
+    Unit *Memory ;
+
+#ifndef NRECIPROCAL
+    Int do_recip = FALSE ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG0 (("KERNEL INIT\n")) ;
+
+    n_row = Symbolic->n_row ;
+    n_col = Symbolic->n_col ;
+    nn = MAX (n_row, n_col) ;
+    n_inner = MIN (n_row, n_col) ;
+    nempty_col = Symbolic->nempty_col ;
+    nempty_row = Symbolic->nempty_row ;
+    nempty = MIN (nempty_row, nempty_col) ;
+    ASSERT (n_row > 0 && n_col > 0) ;
+    Cperm_init = Symbolic->Cperm_init ;
+    Rperm_init = Symbolic->Rperm_init ;
+    Cdeg = Symbolic->Cdeg ;
+    Rdeg = Symbolic->Rdeg ;
+    n1 = Symbolic->n1 ;
+    dense_row_threshold = Symbolic->dense_row_threshold ;
+    DEBUG0 (("Singletons: "ID"\n", n1)) ;
+    Work->nforced = 0 ;
+    Work->ndiscard = 0 ;
+    Work->noff_diagonal = 0 ;
+
+    nz = Ap [n_col] ;
+    if (nz < 0 || Ap [0] != 0 || nz != Symbolic->nz)
+    {
+       DEBUGm4 (("nz or Ap [0] bad\n")) ;
+       return (FALSE) ;        /* pattern changed */
+    }
+
+    prefer_diagonal = Symbolic->prefer_diagonal ;
+    Diagonal_map = Work->Diagonal_map ;
+    Diagonal_imap = Work->Diagonal_imap ;
+
+    /* ---------------------------------------------------------------------- */
+    /* initialize the Numeric->Memory space for LU, elements, and tuples */
+    /* ---------------------------------------------------------------------- */
+
+    UMF_mem_init_memoryspace (Numeric) ;
+    DEBUG1 (("Kernel init head usage, before allocs: "ID"\n", Numeric->ihead)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* initialize the Work and Numeric objects */
+    /* ---------------------------------------------------------------------- */
+
+    /* current front is empty */
+    Work->fnpiv = 0 ;
+    Work->fncols = 0 ;
+    Work->fnrows = 0 ;
+    Work->fncols_max = 0 ;
+    Work->fnrows_max = 0 ;
+    Work->fnzeros = 0 ;
+    Work->fcurr_size = 0 ;
+    Work->fnr_curr = 0 ;
+    Work->fnc_curr = 0 ;
+
+    Work->nz = nz ;
+    Work->prior_element = EMPTY ;
+    Work->ulen = 0 ;
+    Work->llen = 0 ;
+    Work->npiv = n1 ;
+    Work->frontid = 0 ;
+    Work->nextcand = n1 ;
+
+    Memory = Numeric->Memory ;
+    Rperm = Numeric->Rperm ;
+    Cperm = Numeric->Cperm ;
+    Row_degree = Numeric->Rperm ;
+    Col_degree = Numeric->Cperm ;
+    /* Row_tuples = Numeric->Uip ; not needed */
+    Row_tlen   = Numeric->Uilen ;
+    /* Col_tuples = Numeric->Lip ; not needed */
+    Col_tlen   = Numeric->Lilen ;
+
+    Lip = Numeric->Lip ;
+    Uip = Numeric->Uip ;
+    Lilen = Numeric->Lilen ;
+    Uilen = Numeric->Uilen ;
+
+    Frpos = Work->Frpos ;
+    Fcpos = Work->Fcpos ;
+    Wp = Work->Wp ;
+    Wrp = Work->Wrp ;
+
+    D = Numeric->D ;
+    Upos = Numeric->Upos ;
+    Lpos = Numeric->Lpos ;
+    for (k = 0 ; k < n_inner ; k++)
+    {
+       CLEAR (D [k]) ;
+    }
+
+    Rs = Numeric->Rs ;
+
+    for (row = 0 ; row <= n_row ; row++)
+    {
+       Lpos [row] = EMPTY ;
+       /* Row_tuples [row] = 0 ; set in UMF_build_tuples */
+       /* Row_degree [row] = 0 ; initialized below */
+       Row_tlen [row] = 0 ;
+       /* Frpos [row] = EMPTY ;  do this later */
+    }
+
+    for (col = 0 ; col <= n_col ; col++)
+    {
+       Upos [col] = EMPTY ;
+       /* Col_tuples [col] = 0 ; set in UMF_build_tuples */
+       /* Col_degree [col] = 0 ; initialized below */
+       Col_tlen [col] = 0 ;
+       Fcpos [col] = EMPTY ;
+       Wrp [col] = 0 ;
+    }
+    Work->Wrpflag = 1 ;
+
+    /* When cleared, Wp [0..nn] is < 0 */
+    for (i = 0 ; i <= nn ; i++)
+    {
+       Wp [i] = EMPTY ;
+    }
+    /* In col search, Wp [row] is set to a position, which is >= 0. */
+
+    /* When cleared, Wrp [0..n_col] is < Wrpflag */
+    /* In row search, Wrp [col] is set to Wrpflag. */
+
+    /* no need to initialize Wm, Wio, Woi, and Woo */
+
+    /* clear the external degree counters */
+    Work->cdeg0 = 1 ;
+    Work->rdeg0 = 1 ;
+
+    fixQ = Symbolic->fixQ ;
+
+    E = Work->E ;
+
+    Numeric->n_row = n_row ;
+    Numeric->n_col = n_col ;
+    Numeric->npiv = 0 ;
+    Numeric->nnzpiv = 0 ;
+    Numeric->min_udiag = 0.0 ;
+    Numeric->max_udiag = 0.0 ;
+    Numeric->rcond = 0.0 ;
+    Numeric->isize = 0 ;
+    Numeric->nLentries = 0 ;
+    Numeric->nUentries = 0 ;
+    Numeric->lnz = 0 ;
+    Numeric->unz = 0 ;
+    Numeric->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++)
+           {
+               double value ;
+               Entry aij ;
+               row = Ai [p] ;
+               if (row <= ilast || row >= n_row)
+               {
+                   /* invalid matrix, columns must be sorted, no duplicates */
+                   DEBUGm4 (("invalid matrix (Ai)\n")) ;
+                   return (FALSE) ;
+               }
+               ASSIGN (aij, Ax [p], Az [p]) ;
+               APPROX_ABS (value, aij) ;
+               rs = Rs [row] ;
+               if (!SCALAR_IS_NAN (rs))
+               {
+                   if (SCALAR_IS_NAN (value))
+                   {
+                       /* if any entry in the row is NaN, then the scale factor
+                        * is NaN too (for now) and then set to 1.0 below */
+                       Rs [row] = value ;
+                   }
+                   else if (do_max)
+                   {
+                       Rs [row] = MAX (rs, value) ;
+                   }
+                   else
+                   {
+                       Rs [row] += value ;
+                   }
+               }
+               DEBUG4 (("i "ID" j "ID" value %g,  Rs[i]: %g\n",
+                   row, col, value, Rs[row])) ;
+               ilast = row ;
+           }
+       }
+       DEBUG2 (("Rs[0] = %30.20e\n", Rs [0])) ;
+       for (row = 0 ; row < n_row ; row++)
+       {
+           rs = Rs [row] ;
+           if (SCALAR_IS_ZERO (rs) || SCALAR_IS_NAN (rs))
+           {
+               /* don't scale a completely zero row, or one with NaN's */
+               Rs [row] = 1.0 ;
+           }
+       }
+       rsmin = Rs [0] ;
+       rsmax = Rs [0] ;
+       for (row = 0 ; row < n_row ; row++)
+       {
+           DEBUG2 (("sum %30.20e ", Rs [row])) ;
+           rsmin = MIN (rsmin, Rs [row]) ;
+           rsmax = MAX (rsmax, Rs [row]) ;
+           DEBUG2 (("Rs["ID"] = %30.20e\n", row, Rs [row])) ;
+       }
+#ifndef NRECIPROCAL
+       /* multiply by the reciprocal if Rs is not too small */
+       do_recip = (rsmin >= RECIPROCAL_TOLERANCE) ;
+       if (do_recip)
+       {
+           /* invert the scale factors */
+           for (row = 0 ; row < n_row ; row++)
+           {
+               Rs [row] = 1.0 / Rs [row] ;
+           }
+       }
+#endif
+    }
+    else
+    {
+       /* no scaling, rsmin and rsmax not computed */
+       rsmin = -1 ;
+       rsmax = -1 ;
+#ifndef NRECIPROCAL
+       do_recip = FALSE ;
+#endif
+       /* check the input matrix */
+       if (!AMD_valid (n_row, n_col, Ap, Ai))
+       {
+           /* matrix is invalid */
+           return (FALSE) ;
+       }
+    }
+
+    Numeric->rsmin = rsmin ;
+    Numeric->rsmax = rsmax ;
+#ifndef NRECIPROCAL
+    Numeric->do_recip = do_recip ;
+#else
+    Numeric->do_recip = FALSE ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the inverse row Rperm_init permutation (use Frpos as temp) */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG3 (("\n\n===================LOAD_MATRIX:\n")) ;
+
+    for (newrow = 0 ; newrow < n_row ; newrow++)
+    {
+       oldrow = Rperm_init [newrow] ;
+       ASSERT (oldrow >= 0 && oldrow < n_row) ;
+       Frpos [oldrow] = newrow ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the diagonal imap if doing symmetric pivoting */
+    /* ---------------------------------------------------------------------- */
+
+    if (prefer_diagonal)
+    {
+       ASSERT (n_row == n_col) ;
+       ASSERT (nempty_col == Symbolic->nempty_row) ;
+       ASSERT (nempty_col == nempty) ;
+       for (i = 0 ; i < nn ; i++)
+       {
+           Diagonal_map [i] = EMPTY ;
+           Diagonal_imap [i] = EMPTY ;
+       }
+       for (k = n1 ; k < nn - nempty ; k++)
+       {
+           newrow = Symbolic->Diagonal_map [k] ;
+           Diagonal_map [k] = newrow ;
+           Diagonal_imap [newrow] = k ;
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate O (n_row) workspace at the tail end of Memory */
+    /* ---------------------------------------------------------------------- */
+
+    rpi = UMF_mem_alloc_tail_block (Numeric, UNITS (Int *, n_row+1)) ;
+    rpx = UMF_mem_alloc_tail_block (Numeric, UNITS (Entry *, n_row+1)) ;
+    if (!rpi || !rpx)
+    {
+       /* :: pattern change (out of memory for Rpx, Rpx) :: */
+       /* out of memory, which can only mean that the pattern has changed */
+       return (FALSE) ;        /* pattern changed */
+    }
+    Rpi = (Int   **) (Memory + rpx) ;
+    Rpx = (Entry **) (Memory + rpi) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the LU factors for the columns of the singletons */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG1 (("Allocating singletons:\n")) ;
+    for (k = 0 ; k < n1 ; k++)
+    {
+       lnz = Cdeg [k] - 1 ;
+       unz = Rdeg [k] - 1 ;
+
+       DEBUG1 (("Singleton k "ID" pivrow "ID" pivcol "ID" cdeg "ID" rdeg "
+           ID"\n", k, Rperm_init [k], Cperm_init [k], Cdeg [k], Rdeg [k])) ;
+       ASSERT (unz >= 0 && lnz >= 0 && (lnz == 0 || unz == 0)) ;
+       DEBUG1 (("   lnz "ID" unz "ID"\n", lnz, unz)) ;
+
+       size = UNITS (Int, lnz) + UNITS (Entry, lnz)
+            + UNITS (Int, unz) + UNITS (Entry, unz) ;
+       p = UMF_mem_alloc_head_block (Numeric, size) ;
+       DEBUG1 (("Kernel init head usage: "ID"\n", Numeric->ihead)) ;
+       if (!p)
+       {
+           /* :: pattern change (out of memory for singletons) :: */
+           DEBUG0 (("Pattern has gotten larger - kernel init failed\n")) ;
+           return (FALSE) ;    /* pattern changed */
+       }
+
+       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 [pa], Az [pa]) ;
+
+           /* scale the value using the scale factors, Rs */
+           if (do_scale)
+           {
+#ifndef NRECIPROCAL
+               if (do_recip)
+               {
+                   SCALE_RECIP (x, Rs [oldrow]) ;
+               }
+               else
+#endif
+               {
+                   SCALE_DIV (x, Rs [oldrow]) ;
+               }
+           }
+
+           if (newrow == k)
+           {
+               /* this is the pivot entry itself */
+               ASSERT (oldrow == Rperm_init [k]) ;
+               D [k] = x ;
+           }
+           else if (newrow < k)
+           {
+               /* this entry goes in a row of U */
+               DEBUG1 (("Singleton row of U: k "ID" newrow "ID"\n",
+                   k, newrow)) ;
+               if (--(Wp [newrow]) < 0)
+               {
+                   /* :: pattern change (singleton row too long) :: */
+                   DEBUGm4 (("bad U singleton row (too long)\n")) ;
+                   return (FALSE) ;    /* pattern changed */
+               }
+               *(Rpi [newrow]++) = k ;
+               *(Rpx [newrow]++) = x ;
+           }
+           else
+           {
+               /* this entry goes in a column of L */
+               DEBUG1 (("Singleton col of L: k "ID" newrow "ID"\n",
+                   k, newrow)) ;
+               if (llen >= lilen)
+               {
+                   DEBUGm4 (("bad L singleton col (too long)\n")) ;
+                   return (FALSE) ;    /* pattern changed */
+               }
+               Li   [llen] = newrow ;
+               Lval [llen] = x ;
+               llen++ ;
+           }
+       }
+
+       if (llen != lilen)
+       {
+           /* :: pattern change (singleton column too long) :: */
+           DEBUGm4 (("bad L singleton col (too short)\n")) ;
+           return (FALSE) ;    /* pattern changed */
+       }
+
+       /* scale the column of L */
+       if (llen > 0)
+       {
+           pivot_value = D [k] ;
+           UMF_scale (llen, pivot_value, Lval) ;
+       }
+
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the elements and copy the columns of A */
+    /* ---------------------------------------------------------------------- */
+
+    /* also apply the row and column pre-ordering.  */
+    for (k = n1 ; k < n_col ; k++)
+    {
+       /* The newcol is k, which is what the name of the column is in the
+        * UMFPACK kernel.  The user's name for the column is oldcol. */
+       oldcol = Cperm_init [k] ;
+
+       ASSERT (oldcol >= 0 && oldcol < n_col) ;
+
+       p2 = Ap [oldcol+1] ;
+
+       cdeg = Cdeg [k] ;
+       ASSERT (cdeg >= 0) ;
+       ASSERT (IMPLIES (
+           (Symbolic->ordering != UMFPACK_ORDERING_GIVEN) && n1 > 0,
+           cdeg > 1 || cdeg == 0)) ;
+
+       /* if fixQ: set Col_degree to 0 for the NON_PIVOTAL_COL macro */
+       Col_degree [k] = fixQ ? 0 : cdeg ;
+
+       /* get the element for this column (if any) */
+       e = k - n1 + 1 ;
+       if (k < n_col - nempty_col)
+       {
+           esize = Esize ? Esize [k-n1] : cdeg ;
+           if (E [e])
+           {
+               Int ncols, nrows ;
+               Unit *pp ;
+               pp = Memory + E [e] ;
+               GET_ELEMENT (ep, pp, Cols, Rows, ncols, nrows, C) ;
+               ASSERT (ncols == 1) ;
+               ASSERT (nrows == esize) ;
+               ASSERT (Cols [0] == k) ;
+           }
+       }
+       else
+       {
+           ASSERT (cdeg == 0) ;
+           esize = 0 ;
+       }
+
+       clen = 0 ;
+
+       for (pa = Ap [oldcol] ; pa < p2 ; pa++)
+       {
+           oldrow = Ai [pa] ;
+           newrow = Frpos [oldrow] ;
+           ASSIGN (x, Ax [pa], Az [pa]) ;
+
+           /* scale the value using the scale factors, Rs */
+           if (do_scale)
+           {
+#ifndef NRECIPROCAL
+               if (do_recip)
+               {
+                   /* multiply by the reciprocal */
+                   SCALE_RECIP (x, Rs [oldrow]) ;
+               }
+               else
+#endif
+               {
+                   /* divide instead */
+                   SCALE_DIV (x, Rs [oldrow]) ;
+               }
+           }
+
+           rdeg = Rdeg [newrow] ;
+           if (newrow < n1 || rdeg > dense_row_threshold)
+           {
+               /* this entry goes in a row of U or into a dense row */
+               DEBUG1 (("Singleton/dense row of U: k "ID" newrow "ID"\n",
+                   k, newrow)) ;
+               if (--(Wp [newrow]) < 0)
+               {
+                   DEBUGm4 (("bad row of U or A (too long)\n")) ;
+                   return (FALSE) ;    /* pattern changed */
+               }
+               *(Rpi [newrow]++) = k ;
+               *(Rpx [newrow]++) = x ;
+           }
+           else
+           {
+               /* this entry goes in an initial element */
+               DEBUG1 (("In element k "ID" e "ID" newrow "ID"\n",
+                   k, e, newrow)) ;
+               if (clen >= esize)
+               {
+                   DEBUGm4 (("bad A column (too long)\n")) ;
+                   return (FALSE) ;    /* pattern changed */
+               }
+               ASSERT (E [e]) ;
+               ASSERT (k < n_col - nempty_col) ;
+               Rows [clen] = newrow ;
+               C    [clen] = x ;
+               clen++ ;
+#ifndef NDEBUG
+               if (Diagonal_map && (newrow == Diagonal_map [k]))
+               {
+                   DEBUG0 (("Diagonal: old: row "ID" col "ID" : "
+                       "new: row "ID" col "ID" : ",
+                       oldrow, oldcol, newrow, k)) ;
+                   EDEBUGk (0, x) ;
+               }
+#endif
+           }
+       }
+
+       if (clen != esize)
+       {
+           /* :: pattern change (singleton column too short) :: */
+           DEBUGm4 (("bad A column (too short)\n")) ;
+           return (FALSE) ;    /* pattern changed */
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* free the Rpi and Rpx workspace at the tail end of memory */
+    /* ---------------------------------------------------------------------- */
+
+    UMF_mem_free_tail_block (Numeric, rpi) ;
+    UMF_mem_free_tail_block (Numeric, rpx) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* prune zeros 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) ;
+       }
+    }
+
+#ifndef NDEBUG
+    if (prefer_diagonal)
+    {
+       Int *InvCperm, newcol ;
+       Entry aij ;
+       UMF_dump_diagonal_map (Diagonal_map, Diagonal_imap, n1, nn, nempty) ;
+       InvCperm = (Int *) malloc (n_col * sizeof (Int)) ;
+       ASSERT (InvCperm != (Int *) NULL) ;
+       for (newcol = 0 ; newcol < n_col ; newcol++)
+       {
+           oldcol = Cperm_init [newcol] ;
+           InvCperm [oldcol] = newcol ;
+       }
+       DEBUGm3 (("Diagonal of P2*A:\n")) ;
+       for (oldcol = 0 ; oldcol < n_col ; oldcol++)
+       {
+           newcol = InvCperm [oldcol] ;
+           for (p = Ap [oldcol] ; p < Ap [oldcol+1] ; p++)
+           {
+               oldrow = Ai [p] ;
+               newrow = Frpos [oldrow] ;
+               ASSIGN (aij, Ax [p], Az [p]) ;
+               if (newrow == Diagonal_map [newcol])
+               {
+                   DEBUG0 (("old row "ID" col "ID" new row "ID" col "ID,
+                       oldrow, oldcol, newrow, newcol)) ;
+                   EDEBUGk (0, aij) ;
+                   DEBUG0 ((" scaled ")) ;
+                   if (do_scale)
+                   {
+#ifndef NRECIPROCAL
+                       if (do_recip)
+                       {
+                           SCALE_RECIP (aij, Rs [oldrow]) ;
+                       }
+                       else
+#endif
+                       {
+                           SCALE_DIV (aij, Rs [oldrow]) ;
+                       }
+                   }
+                   EDEBUGk (0, aij) ;
+                   DEBUG0 (("\n")) ;
+               }
+           }
+       }
+       free (InvCperm) ;
+    }
+#endif
+
+    Col_degree [n_col] = 0 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* pack the element name space */
+    /* ---------------------------------------------------------------------- */
+
+    if (empty_elements)
+    {
+       Int e2 = 0 ;
+       DEBUG0 (("\n\n============= Packing element space\n")) ;
+       for (e = 1 ; e <= Work->nel ; e++)
+       {
+           if (E [e])
+           {
+               e2++ ;
+               E [e2] = E [e] ;
+           }
+       }
+       Work->nel = e2 ;
+    }
+
+#ifndef NDEBUG
+    DEBUG0 (("Number of initial elements: "ID"\n", Work->nel)) ;
+    for (e = 0 ; e <= Work->nel ; e++) UMF_dump_element (Numeric, Work,e,TRUE) ;
+#endif
+
+    for (e = Work->nel + 1 ; e < Work->elen ; e++)
+    {
+       E [e] = 0 ;
+    }
+
+    /* Frpos no longer needed */
+    for (row = 0 ; row <= n_row ; row++)
+    {
+       Frpos [row] = EMPTY ;
+    }
+
+    /* clear Wp */
+    for (i = 0 ; i <= nn ; i++)
+    {
+       Wp [i] = EMPTY ;
+    }
+
+    DEBUG1 (("Kernel init head usage: "ID"\n", Numeric->ihead)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* build the tuple lists */
+    /* ---------------------------------------------------------------------- */
+
+    /* if the memory usage changes, then the pattern has changed */
+
+    (void) UMF_tuple_lengths (Numeric, Work, &unused) ;
+    if (!UMF_build_tuples (Numeric, Work))
+    {
+       /* :: pattern change (out of memory in umf_build_tuples) :: */
+       /* We ran out of memory, which can only mean that */
+       /* the pattern (Ap and or Ai) has changed (gotten larger). */
+       DEBUG0 (("Pattern has gotten larger - build tuples failed\n")) ;
+       return (FALSE) ;        /* pattern changed */
+    }
+
+    Numeric->init_usage = Numeric->max_usage ;
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the row merge sets */
+    /* ---------------------------------------------------------------------- */
+
+    for (i = 0 ; i <= Symbolic->nfr ; i++)
+    {
+       Work->Front_new1strow [i] = Symbolic->Front_1strow [i] ;
+    }
+
+#ifndef NDEBUG
+    UMF_dump_rowmerge (Numeric, Symbolic, Work) ;
+    DEBUG6 (("Column form of original matrix:\n")) ;
+    UMF_dump_col_matrix (Ax,
+#ifdef COMPLEX
+       Az,
+#endif
+       Ai, Ap, n_row, n_col, nz) ;
+    UMF_dump_memory (Numeric) ;
+    UMF_dump_matrix (Numeric, Work, FALSE) ;
+    DEBUG0 (("kernel init done...\n")) ;
+#endif
+
+    return (TRUE) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel_init.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel_init.h
new file mode 100644 (file)
index 0000000..67deb41
--- /dev/null
@@ -0,0 +1,19 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_kernel_init
+(
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const double Ax [ ],
+#ifdef COMPLEX
+    const double Az [ ],
+#endif
+    NumericType *Numeric,
+    WorkType *Work,
+    SymbolicType *Symbolic
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel_wrapup.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel_wrapup.c
new file mode 100644 (file)
index 0000000..6b32a1b
--- /dev/null
@@ -0,0 +1,466 @@
+/* ========================================================================== */
+/* === UMF_kernel_wrapup ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* The matrix is factorized.  Finish the LU data structure. */
+
+#include "umf_internal.h"
+
+GLOBAL void UMF_kernel_wrapup
+(
+    NumericType *Numeric,
+    SymbolicType *Symbolic,
+    WorkType *Work
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int i, k, col, row, llen, ulen, *ip, *Rperm, *Cperm, *Lilen, npiv, lp,
+       *Uilen, *Lip, *Uip, *Cperm_init, up, pivrow, pivcol, *Lpos, *Upos, *Wr,
+       *Wc, *Wp, *Frpos, *Fcpos, *Row_degree, *Col_degree, *Rperm_init,
+       n_row, n_col, n_inner, zero_pivot, nan_pivot, n1 ;
+    Entry *D, pivot_value ;
+    double d ;
+
+#ifndef NDEBUG
+    UMF_dump_matrix (Numeric, Work, FALSE) ;
+#endif
+
+    DEBUG0 (("Kernel complete, Starting Kernel wrapup\n")) ;
+    n_row = Symbolic->n_row ;
+    n_col = Symbolic->n_col ;
+    n_inner = MIN (n_row, n_col) ;
+    Rperm = Numeric->Rperm ;
+    Cperm = Numeric->Cperm ;
+    Lilen = Numeric->Lilen ;
+    Uilen = Numeric->Uilen ;
+    Upos = Numeric->Upos ;
+    Lpos = Numeric->Lpos ;
+    Lip = Numeric->Lip ;
+    Uip = Numeric->Uip ;
+    D = Numeric->D ;
+
+    npiv = Work->npiv ;
+    Numeric->npiv = npiv ;
+    Numeric->ulen = Work->ulen ;
+
+    ASSERT (n_row == Numeric->n_row) ;
+    ASSERT (n_col == Symbolic->n_col) ;
+    DEBUG0 (("Wrap-up: npiv "ID" ulen "ID"\n", npiv, Numeric->ulen)) ;
+    ASSERT (npiv <= n_inner) ;
+
+    /* this will be nonzero only if matrix is singular or rectangular */
+    ASSERT (IMPLIES (npiv == n_col, Work->ulen == 0)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* find the smallest and largest entries in D */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = 0 ; k < npiv ; k++)
+    {
+       pivot_value = D [k] ;
+       ABS (d, pivot_value) ;
+       zero_pivot = SCALAR_IS_ZERO (d) ;
+       nan_pivot = SCALAR_IS_NAN (d) ;
+
+       if (!zero_pivot)
+       {
+           /* the pivot is nonzero, but might be Inf or NaN */
+           Numeric->nnzpiv++ ;
+       }
+
+       if (k == 0)
+       {
+           Numeric->min_udiag = d ;
+           Numeric->max_udiag = d ;
+       }
+       else
+       {
+           /* min (abs (diag (U))) behaves as follows:  If any entry is zero,
+              then the result is zero (regardless of the presence of NaN's).
+              Otherwise, if any entry is NaN, then the result is NaN.
+              Otherwise, the result is the smallest absolute value on the
+              diagonal of U.
+           */
+
+           if (SCALAR_IS_NONZERO (Numeric->min_udiag))
+           {
+               if (zero_pivot || nan_pivot)
+               {
+                   Numeric->min_udiag = d ;
+               }
+               else if (!SCALAR_IS_NAN (Numeric->min_udiag))
+               {
+                   /* d and min_udiag are both non-NaN */
+                   Numeric->min_udiag = MIN (Numeric->min_udiag, d) ;
+               }
+           }
+
+           /*
+              max (abs (diag (U))) behaves as follows:  If any entry is NaN
+              then the result is NaN.  Otherise, the result is the largest
+              absolute value on the diagonal of U.
+           */
+
+           if (nan_pivot)
+           {
+               Numeric->max_udiag = d ;
+           }
+           else if (!SCALAR_IS_NAN (Numeric->max_udiag))
+           {
+               /* d and max_udiag are both non-NaN */
+               Numeric->max_udiag = MAX (Numeric->max_udiag, d) ;
+           }
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* check if matrix is singular or rectangular */
+    /* ---------------------------------------------------------------------- */
+
+    Col_degree = Cperm ;       /* for NON_PIVOTAL_COL macro */
+    Row_degree = Rperm ;       /* for NON_PIVOTAL_ROW macro */
+
+    if (npiv < n_row)
+    {
+       /* finalize the row permutation */
+       k = npiv ;
+       DEBUGm3 (("Singular pivot rows "ID" to "ID"\n", k, n_row-1)) ;
+       for (row = 0 ; row < n_row ; row++)
+       {
+           if (NON_PIVOTAL_ROW (row))
+           {
+               Rperm [row] = ONES_COMPLEMENT (k) ;
+               DEBUGm3 (("Singular row "ID" is k: "ID" pivot row\n", row, k)) ;
+               ASSERT (!NON_PIVOTAL_ROW (row)) ;
+               Lpos [row] = EMPTY ;
+               Uip [row] = EMPTY ;
+               Uilen [row] = 0 ;
+               k++ ;
+           }
+       }
+       ASSERT (k == n_row) ;
+    }
+
+    if (npiv < n_col)
+    {
+       /* finalize the col permutation */
+       k = npiv ;
+       DEBUGm3 (("Singular pivot cols "ID" to "ID"\n", k, n_col-1)) ;
+       for (col = 0 ; col < n_col ; col++)
+       {
+           if (NON_PIVOTAL_COL (col))
+           {
+               Cperm [col] = ONES_COMPLEMENT (k) ;
+               DEBUGm3 (("Singular col "ID" is k: "ID" pivot row\n", col, k)) ;
+               ASSERT (!NON_PIVOTAL_COL (col)) ;
+               Upos [col] = EMPTY ;
+               Lip [col] = EMPTY ;
+               Lilen [col] = 0 ;
+               k++ ;
+           }
+       }
+       ASSERT (k == n_col) ;
+    }
+
+    if (npiv < n_inner)
+    {
+       /* finalize the diagonal of U */
+       DEBUGm3 (("Diag of U is zero, "ID" to "ID"\n", npiv, n_inner-1)) ;
+       for (k = npiv ; k < n_inner ; k++)
+       {
+           CLEAR (D [k]) ;
+       }
+    }
+
+    /* save the pattern of the last row of U */
+    if (Numeric->ulen > 0)
+    {
+       DEBUGm3 (("Last row of U is not empty\n")) ;
+       Numeric->Upattern = Work->Upattern ;
+       Work->Upattern = (Int *) NULL ;
+    }
+
+    DEBUG2 (("Nnzpiv: "ID"  npiv "ID"\n", Numeric->nnzpiv, npiv)) ;
+    ASSERT (Numeric->nnzpiv <= npiv) ;
+    if (Numeric->nnzpiv < n_inner && !SCALAR_IS_NAN (Numeric->min_udiag))
+    {
+       /* the rest of the diagonal is zero, so min_udiag becomes 0,
+        * unless it is already NaN. */
+       Numeric->min_udiag = 0.0 ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* size n_row, n_col workspaces that can be used here: */
+    /* ---------------------------------------------------------------------- */
+
+    Frpos = Work->Frpos ;      /* of size n_row+1 */
+    Fcpos = Work->Fcpos ;      /* of size n_col+1 */
+    Wp = Work->Wp ;            /* of size MAX(n_row,n_col)+1 */
+    /* Work->Upattern ;                cannot be used (in Numeric) */
+    Wr = Work->Lpattern ;      /* of size n_row+1 */
+    Wc = Work->Wrp ;           /* of size n_col+1 or bigger */
+
+    /* ---------------------------------------------------------------------- */
+    /* construct Rperm from inverse permutations */
+    /* ---------------------------------------------------------------------- */
+
+    /* use Frpos for temporary copy of inverse row permutation [ */
+
+    for (pivrow = 0 ; pivrow < n_row ; pivrow++)
+    {
+       k = Rperm [pivrow] ;
+       ASSERT (k < 0) ;
+       k = ONES_COMPLEMENT (k) ;
+       ASSERT (k >= 0 && k < n_row) ;
+       Wp [k] = pivrow ;
+       Frpos [pivrow] = k ;
+    }
+    for (k = 0 ; k < n_row ; k++)
+    {
+       Rperm [k] = Wp [k] ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* construct Cperm from inverse permutation */
+    /* ---------------------------------------------------------------------- */
+
+    /* use Fcpos for temporary copy of inverse column permutation [ */
+
+    for (pivcol = 0 ; pivcol < n_col ; pivcol++)
+    {
+       k = Cperm [pivcol] ;
+       ASSERT (k < 0) ;
+       k = ONES_COMPLEMENT (k) ;
+       ASSERT (k >= 0 && k < n_col) ;
+       Wp [k] = pivcol ;
+       /* save a copy of the inverse column permutation in Fcpos */
+       Fcpos [pivcol] = k ;
+    }
+    for (k = 0 ; k < n_col ; k++)
+    {
+       Cperm [k] = Wp [k] ;
+    }
+
+#ifndef NDEBUG
+    for (k = 0 ; k < n_col ; k++)
+    {
+       col = Cperm [k] ;
+       ASSERT (col >= 0 && col < n_col) ;
+       ASSERT (Fcpos [col] == k) ;             /* col is the kth pivot */
+    }
+    for (k = 0 ; k < n_row ; k++)
+    {
+       row = Rperm [k] ;
+       ASSERT (row >= 0 && row < n_row) ;
+       ASSERT (Frpos [row] == k) ;             /* row is the kth pivot */
+    }
+#endif
+
+#ifndef NDEBUG
+    UMF_dump_lu (Numeric) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* permute Lpos, Upos, Lilen, Lip, Uilen, and Uip */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = 0 ; k < npiv ; k++)
+    {
+       pivrow = Rperm [k] ;
+       Wr [k] = Uilen [pivrow] ;
+       Wp [k] = Uip [pivrow] ;
+    }
+
+    for (k = 0 ; k < npiv ; k++)
+    {
+       Uilen [k] = Wr [k] ;
+       Uip [k] = Wp [k] ;
+    }
+
+    for (k = 0 ; k < npiv ; k++)
+    {
+       pivrow = Rperm [k] ;
+       Wp [k] = Lpos [pivrow] ;
+    }
+
+    for (k = 0 ; k < npiv ; k++)
+    {
+       Lpos [k] = Wp [k] ;
+    }
+
+    for (k = 0 ; k < npiv ; k++)
+    {
+       pivcol = Cperm [k] ;
+       Wc [k] = Lilen [pivcol] ;
+       Wp [k] = Lip [pivcol] ;
+    }
+
+    for (k = 0 ; k < npiv ; k++)
+    {
+       Lilen [k] = Wc [k] ;
+       Lip [k] = Wp [k] ;
+    }
+
+    for (k = 0 ; k < npiv ; k++)
+    {
+       pivcol = Cperm [k] ;
+       Wp [k] = Upos [pivcol] ;
+    }
+
+    for (k = 0 ; k < npiv ; k++)
+    {
+       Upos [k] = Wp [k] ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* terminate the last Uchain and last Lchain */
+    /* ---------------------------------------------------------------------- */
+
+    Upos [npiv] = EMPTY ;
+    Lpos [npiv] = EMPTY ;
+    Uip [npiv] = EMPTY ;
+    Lip [npiv] = EMPTY ;
+    Uilen [npiv] = 0 ;
+    Lilen [npiv] = 0 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* convert U to the new pivot order */
+    /* ---------------------------------------------------------------------- */
+
+    n1 = Symbolic->n1 ;
+
+    for (k = 0 ; k < n1 ; k++)
+    {
+       /* this is a singleton row of U */
+       ulen = Uilen [k] ;
+       DEBUG4 (("K "ID" New U.  ulen "ID" Singleton 1\n", k, ulen)) ;
+       if (ulen > 0)
+       {
+           up = Uip [k] ;
+           ip = (Int *) (Numeric->Memory + up) ;
+           for (i = 0 ; i < ulen ; i++)
+           {
+               col = *ip ;
+               DEBUG4 ((" old col "ID" new col "ID"\n", col, Fcpos [col]));
+               ASSERT (col >= 0 && col < n_col) ;
+               *ip++ = Fcpos [col] ;
+           }
+       }
+    }
+
+    for (k = n1 ; k < npiv ; k++)
+    {
+       up = Uip [k] ;
+       if (up < 0)
+       {
+           /* this is the start of a new Uchain (with a pattern) */
+           ulen = Uilen [k] ;
+           DEBUG4 (("K "ID" New U.  ulen "ID" End_Uchain 1\n", k, ulen)) ;
+           if (ulen > 0)
+           {
+               up = -up ;
+               ip = (Int *) (Numeric->Memory + up) ;
+               for (i = 0 ; i < ulen ; i++)
+               {
+                   col = *ip ;
+                   DEBUG4 ((" old col "ID" new col "ID"\n", col, Fcpos [col]));
+                   ASSERT (col >= 0 && col < n_col) ;
+                   *ip++ = Fcpos [col] ;
+               }
+           }
+       }
+    }
+
+    ulen = Numeric->ulen ;
+    if (ulen > 0)
+    {
+       /* convert last pivot row of U to the new pivot order */
+       DEBUG4 (("K "ID" (last)\n", k)) ;
+       for (i = 0 ; i < ulen ; i++)
+       {
+           col = Numeric->Upattern [i] ;
+           DEBUG4 (("    old col "ID" new col "ID"\n", col, Fcpos [col])) ;
+           Numeric->Upattern [i] = Fcpos [col] ;
+       }
+    }
+
+    /* Fcpos no longer needed ] */
+
+    /* ---------------------------------------------------------------------- */
+    /* convert L to the new pivot order */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = 0 ; k < n1 ; k++)
+    {
+       llen = Lilen [k] ;
+       DEBUG4 (("K "ID" New L.  llen "ID" Singleton col\n", k, llen)) ;
+       if (llen > 0)
+       {
+           lp = Lip [k] ;
+           ip = (Int *) (Numeric->Memory + lp) ;
+           for (i = 0 ; i < llen ; i++)
+           {
+               row = *ip ;
+               DEBUG4 (("    old row "ID" new row "ID"\n", row, Frpos [row])) ;
+               ASSERT (row >= 0 && row < n_row) ;
+               *ip++ = Frpos [row] ;
+           }
+       }
+    }
+
+    for (k = n1 ; k < npiv ; k++)
+    {
+       llen = Lilen [k] ;
+       DEBUG4 (("K "ID" New L.  llen "ID" \n", k, llen)) ;
+       if (llen > 0)
+       {
+           lp = Lip [k] ;
+           if (lp < 0)
+           {
+               /* this starts a new Lchain */
+               lp = -lp ;
+           }
+           ip = (Int *) (Numeric->Memory + lp) ;
+           for (i = 0 ; i < llen ; i++)
+           {
+               row = *ip ;
+               DEBUG4 (("    old row "ID" new row "ID"\n", row, Frpos [row])) ;
+               ASSERT (row >= 0 && row < n_row) ;
+               *ip++ = Frpos [row] ;
+           }
+       }
+    }
+
+    /* Frpos no longer needed ] */
+
+    /* ---------------------------------------------------------------------- */
+    /* combine symbolic and numeric permutations */
+    /* ---------------------------------------------------------------------- */
+
+    Cperm_init = Symbolic->Cperm_init ;
+    Rperm_init = Symbolic->Rperm_init ;
+
+    for (k = 0 ; k < n_row ; k++)
+    {
+       Rperm [k] = Rperm_init [Rperm [k]] ;
+    }
+
+    for (k = 0 ; k < n_col ; k++)
+    {
+       Cperm [k] = Cperm_init [Cperm [k]] ;
+    }
+
+    /* Work object will be freed immediately upon return (to UMF_kernel */
+    /* and then to UMFPACK_numeric). */
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel_wrapup.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel_wrapup.h
new file mode 100644 (file)
index 0000000..4550821
--- /dev/null
@@ -0,0 +1,13 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_kernel_wrapup
+(
+    NumericType *Numeric,
+    SymbolicType *Symbolic,
+    WorkType *Work
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_local_search.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_local_search.c
new file mode 100644 (file)
index 0000000..7c54cd2
--- /dev/null
@@ -0,0 +1,1949 @@
+/* ========================================================================== */
+/* === UMF_local_search ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Perform pivot search to find pivot row and pivot column.
+    The pivot column is selected from the candidate set.  The candidate set
+    corresponds to a supercolumn from colamd or UMF_analyze.  The pivot column
+    is then removed from that set.  Constructs the pivot column pattern and
+    values.  Called by umf_kernel.  Returns UMFPACK_OK if successful, or
+    UMFPACK_WARNING_singular_matrix or UMFPACK_ERROR_different_pattern if not.
+*/
+
+#include "umf_internal.h"
+#include "umf_row_search.h"
+#include "umf_mem_free_tail_block.h"
+
+/* Version 4.1:  relaxed amalgamation control parameters are now fixed, and
+ * cannot be changed via Control [..] settings, as they could in Version 4.0. */
+#define RELAX1 0.25        /* this was UMFPACK_DEFAULT_RELAXED_AMALGAMATION */
+#define SYM_RELAX1 0.0     /* this is new to Version 4.1 */
+#define RELAX2 0.1         /* this was UMFPACK_DEFAULT_RELAXED2_AMALGAMATION */
+#define RELAX3 0.125       /* this was UMFPACK_DEFAULT_RELAXED3_AMALGAMATION */
+
+/* ========================================================================== */
+/* === remove_candidate ===================================================== */
+/* ========================================================================== */
+
+/* Remove a column from the set of candidate pivot columns. */
+
+PRIVATE void remove_candidate (Int jj, WorkType *Work, SymbolicType *Symbolic)
+{
+
+#ifndef NDEBUG
+    Int j ;
+    DEBUGm2 (("pivot column Candidates before remove: nCand "ID" ncand "ID
+       " lo "ID" hi "ID" jj "ID"\n", Work->nCandidates, Work->ncand,
+       Work->lo, Work->hi, jj)) ;
+    for (j = 0 ; j < Work->nCandidates ; j++)
+    {
+       Int col = Work->Candidates [j] ;
+       DEBUGm2 ((ID" ", col));
+       ASSERT (col >= 0 && col < Work->n_col) ;
+       /* ASSERT (NON_PIVOTAL_COL (col)) ; */
+       ASSERT (col >= Work->lo && col <= Work->hi) ;
+    }
+    DEBUGm2 (("\n")) ;
+#endif
+
+    if (Symbolic->fixQ)
+    {
+       DEBUGm2 (("FixQ\n")) ;
+       /* do not modify the column ordering */
+       ASSERT (Work->nCandidates == 1) ;
+       ASSERT (jj == 0) ;
+       if (Work->ncand > 1)
+       {
+           Work->Candidates [0] = Work->nextcand++ ;
+       }
+       else
+       {
+           Work->nCandidates = 0 ;
+       }
+    }
+    else
+    {
+       /* place the next candidate in the set */
+       if (Work->ncand > MAX_CANDIDATES)
+       {
+           Work->Candidates [jj] = Work->nextcand++ ;
+       }
+       else
+       {
+           ASSERT (Work->nCandidates == Work->ncand) ;
+           Work->Candidates [jj] = Work->Candidates [Work->ncand - 1] ;
+           Work->Candidates [Work->ncand - 1] = EMPTY ;
+           Work->nCandidates-- ;
+       }
+    }
+    Work->ncand-- ;
+
+#ifndef NDEBUG
+    DEBUGm2 (("pivot column Candidates after remove: nCand "ID" ncand "ID
+       " lo "ID" hi "ID" jj "ID"\n", Work->nCandidates, Work->ncand, Work->lo,
+       Work->hi, jj)) ;
+    for (j = 0 ; j < Work->nCandidates ; j++)
+    {
+       Int col = Work->Candidates [j] ;
+       DEBUGm2 ((ID" ", col));
+       ASSERT (col >= 0 && col < Work->n_col) ;
+       /* ASSERT (NON_PIVOTAL_COL (col)) ; */
+       ASSERT (col >= Work->lo && col <= Work->hi) ;
+    }
+    DEBUGm2 (("\n")) ;
+    ASSERT (Work->ncand >= 0) ;
+    ASSERT (Work->nCandidates <= Work->ncand) ;
+#endif
+}
+
+/* ========================================================================== */
+/* === UMF_local_search ===================================================== */
+/* ========================================================================== */
+
+GLOBAL Int UMF_local_search
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    SymbolicType *Symbolic
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Entry *Flblock, *Fublock, *Fs, *Fcblock, *C, *Wx, *Wy, *Fu, *Flublock,
+       *Flu ;
+    double relax1 ;
+    Int pos, nrows, *Cols, *Rows, e, f, status, max_cdeg, fnzeros, nb, j, col,
+       i, row, cdeg_in, rdeg [2][2], fnpiv, nothing [2], new_LUsize,
+       pivrow [2][2], pivcol [2], *Wp, *Fcpos, *Frpos, new_fnzeros, cdeg_out,
+       *Wm, *Wio, *Woi, *Woo, *Frows, *Fcols, fnrows, fncols, *E, deg, nr_in,
+       nc, thiscost, bestcost, nr_out, do_update, extra_cols, extra_rows,
+       extra_zeros, relaxed_front, do_extend, fnr_curr, fnc_curr, tpi,
+       *Col_tuples, *Col_degree, *Col_tlen, jj, jcand [2], freebie [2],
+       did_rowmerge, fnrows_new [2][2], fncols_new [2][2], search_pivcol_out,
+       *Diagonal_map, *Diagonal_imap, row2, col2 ;
+    Unit *Memory, *p ;
+    Tuple *tp, *tpend, *tp1, *tp2 ;
+    Element *ep ;
+
+#ifndef NDEBUG
+    Int debug_ok, n_row, n_col, *Row_degree ;
+    Row_degree = Numeric->Rperm ;      /* for NON_PIVOTAL_ROW macro only */
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    Memory = Numeric->Memory ;
+    E = Work->E ;
+    Col_degree = Numeric->Cperm ;
+
+    Col_tuples = Numeric->Lip ;
+    Col_tlen   = Numeric->Lilen ;
+
+    Wx = Work->Wx ;
+    Wy = Work->Wy ;
+    Wp = Work->Wp ;
+    Wm = Work->Wm ;
+    Woi = Work->Woi ;
+    Wio = Work->Wio ;
+    Woo = Work->Woo ;
+    Fcpos = Work->Fcpos ;
+    Frpos = Work->Frpos ;
+    Frows = Work->Frows ;
+    Fcols = Work->Fcols ;
+    fnrows = Work->fnrows ;
+    fncols = Work->fncols ;
+    nb = Work->nb ;
+    fnr_curr = Work->fnr_curr ;
+    fnc_curr = Work->fnc_curr ;
+    fnpiv = Work->fnpiv ;
+    nothing [0] = EMPTY ;
+    nothing [1] = EMPTY ;
+    relax1 = (Symbolic->prefer_diagonal) ? SYM_RELAX1 : RELAX1 ;
+    fnzeros = Work->fnzeros ;
+    new_fnzeros = fnzeros ;
+    jj = EMPTY ;
+
+    Fcblock = Work->Fcblock ;      /* current contribution block */
+    Flblock = Work->Flblock ;      /* current L block */
+    Fublock = Work->Fublock ;      /* current U block */
+    Flublock = Work->Flublock ;            /* current LU block */
+
+    /* The pivot column degree cannot exceed max_cdeg */
+    max_cdeg = Work->fnrows_max ;
+    ASSERT (Work->fnrows_max <= Symbolic->maxnrows) ;
+    ASSERT (Work->fncols_max <= Symbolic->maxncols) ;
+
+    if (fnrows == 0 && fncols == 0)
+    {
+       /* frontal matrix is empty */
+       Work->firstsuper = Work->ksuper ;
+    }
+
+#ifndef NDEBUG
+    n_row = Work->n_row ;
+    n_col = Work->n_col ;
+    DEBUG2 (("\n========LOCAL SEARCH:  current frontal matrix: ========= \n")) ;
+    UMF_dump_current_front (Numeric, Work, TRUE) ;
+    if (UMF_debug > 0 || MAX (n_row, n_col) < 1000)
+    {
+       for (i = 0 ; i < MAX (n_row, n_col) ; i++)
+       {
+           ASSERT (Wp [i] < 0) ;
+       }
+    }
+
+    DEBUGm2 ((ID" pivot column Candidates: lo "ID" hi "ID"\n",
+       Work->nCandidates, Work->lo, Work->hi)) ;
+    for (j = 0 ; j < Work->nCandidates ; j++)
+    {
+       col = Work->Candidates [j] ;
+       DEBUGm2 ((ID" ", col));
+       ASSERT (col >= 0 && col < n_col) ;
+       ASSERT (NON_PIVOTAL_COL (col)) ;
+       ASSERT (col >= Work->lo && col <= Work->hi) ;
+    }
+
+    DEBUGm2 (("\n")) ;
+    /* there are no 0-by-c or r-by-0 fronts, where c and r are > 0 */
+    /* a front is either 0-by-0, or r-by-c */
+    DEBUG2 (("\n\n::: "ID" : Npiv: "ID" + fnpiv "ID" = "ID". "
+       "size "ID"-by-"ID"\n", Work->frontid,
+       Work->npiv, Work->fnpiv, Work->npiv + Work->fnpiv, fnrows, fncols)) ;
+    ASSERT ((fnrows == 0 && fncols == 0) ||(fnrows != 0 && fncols != 0)) ;
+#endif
+
+    /* ====================================================================== */
+    /* === PIVOT SEARCH ===================================================== */
+    /* ====================================================================== */
+
+    /* initialize */
+
+    pivcol [IN] = EMPTY ;
+    pivcol [OUT] = EMPTY ;
+
+    cdeg_in = Int_MAX ;
+    cdeg_out = Int_MAX ;
+
+    pivrow [IN][IN] = EMPTY ;
+    pivrow [IN][OUT] = EMPTY ;
+    pivrow [OUT][IN] = EMPTY ;
+    pivrow [OUT][OUT] = EMPTY ;
+
+    rdeg [IN][IN] = Int_MAX ;
+    rdeg [IN][OUT] = Int_MAX ;
+    rdeg [OUT][IN] = Int_MAX ;
+    rdeg [OUT][OUT] = Int_MAX ;
+
+    freebie [IN] = FALSE ;
+    freebie [OUT] = FALSE ;
+
+    Work->pivot_case = EMPTY ;
+    bestcost = EMPTY ;
+
+    nr_out = EMPTY ;
+    nr_in = EMPTY ;
+
+    jcand [IN] = EMPTY ;
+    jcand [OUT] = EMPTY ;
+
+    fnrows_new [IN][IN] = EMPTY ;
+    fnrows_new [IN][OUT] = EMPTY ;
+    fnrows_new [OUT][IN] = EMPTY ;
+    fnrows_new [OUT][OUT] = EMPTY ;
+
+    fncols_new [IN][IN] = EMPTY ;
+    fncols_new [IN][OUT] = EMPTY ;
+    fncols_new [OUT][IN] = EMPTY ;
+    fncols_new [OUT][OUT] = EMPTY ;
+
+#ifndef NDEBUG
+       /* check Frpos */
+       DEBUG4 (("Check Frpos : fnrows "ID" col "ID" maxcdeg "ID"\n",
+               fnrows, pivcol [IN], max_cdeg)) ;
+       for (i = 0 ; i < fnrows ; i++)
+       {
+           row = Frows [i] ;
+           DEBUG4 (("  row: "ID"\n", row)) ;
+           ASSERT (row >= 0 && row < n_row) ;
+           ASSERT (Frpos [row] == i) ;
+       }
+       DEBUG4 (("All:\n")) ;
+       if (UMF_debug > 0 || n_row < 1000)
+       {
+           Int cnt = fnrows ;
+           for (row = 0 ; row < n_row ; row++)
+           {
+               if (Frpos [row] == EMPTY)
+               {
+                   cnt++ ;
+               }
+               else
+               {
+                   DEBUG4 (("  row: "ID" pos "ID"\n", row, Frpos [row])) ;
+               }
+           }
+           ASSERT (cnt == n_row) ;
+       }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* find shortest column in the front, and shortest column not in the */
+    /* front, from the candidate pivot column set */
+    /* ---------------------------------------------------------------------- */
+
+    /* If there are too many candidates, then only look at the first */
+    /* MAX_CANDIDATES of them.   Otherwise, if there are O(n) candidates, */
+    /* this code could take O(n^2) time. */
+
+    /* ------------------------------------------------------------------ */
+    /* look in the candidate set for the best column */
+    /* ------------------------------------------------------------------ */
+
+    DEBUG2 (("Max candidates %d, Work->ncand "ID" jmax "ID"\n",
+       MAX_CANDIDATES, Work->ncand, Work->nCandidates)) ;
+    col = Work->Candidates [0] ;
+    ASSERT (Work->nCandidates > 0) ;
+    DEBUG3 (("Pivot column candidate: "ID" j = "ID"\n", col, j)) ;
+    ASSERT (col >= 0 && col < n_col) ;
+
+    /* there is no Col_degree if fixQ is true */
+    deg = Symbolic->fixQ ? EMPTY : Col_degree [col] ;
+
+#ifndef NDEBUG
+    DEBUG3 (("Pivot column candidate: "ID" cost: "ID"  Fcpos[col] "ID"\n",
+       col, deg, Fcpos [col])) ;
+    UMF_dump_rowcol (1, Numeric, Work, col, !Symbolic->fixQ) ;
+    if (Symbolic->fixQ)
+    {
+       DEBUG1 (("FIXQ: Candidates "ID" pivcol "ID" npiv "ID" fnpiv "ID
+           " ndiscard "ID "\n", Work->nCandidates, col, Work->npiv,
+           Work->fnpiv, Work->ndiscard)) ;
+       ASSERT (Work->nCandidates == 1) ;
+       ASSERT (col == Work->npiv + Work->fnpiv + Work->ndiscard) ;
+    }
+#endif
+
+    if (Fcpos [col] >= 0)
+    {
+       /* best column in front, so far */
+       pivcol [IN] = col ;
+       cdeg_in = deg ;         /* ignored, if fixQ is true */
+       jcand [IN] = 0 ;
+    }
+    else
+    {
+       /* best column not in front, so far */
+       pivcol [OUT] = col ;
+       cdeg_out = deg ;        /* ignored, if fixQ is true */
+       jcand [OUT] = 0 ;
+    }
+
+    /* look at the rest of the candidates */
+    for (j = 1 ; j < Work->nCandidates ; j++)
+    {
+       col = Work->Candidates [j] ;
+
+       DEBUG3 (("Pivot col candidate: "ID" j = "ID"\n", col, j)) ;
+       ASSERT (col >= 0 && col < n_col) ;
+       ASSERT (!Symbolic->fixQ) ;
+       deg = Col_degree [col] ;
+#ifndef NDEBUG
+       DEBUG3 (("Pivot col candidate: "ID" cost: "ID" Fcpos[col] "ID"\n",
+               col, deg, Fcpos [col])) ;
+       UMF_dump_rowcol (1, Numeric, Work, col, !Symbolic->fixQ) ;
+#endif
+       if (Fcpos [col] >= 0)
+       {
+#ifndef NDEBUG
+           Int fs ;
+           fs = Fcpos [col] / fnr_curr ;
+           ASSERT (fs >= 0 && fs < fncols) ;
+#endif
+           if (deg < cdeg_in || (deg == cdeg_in && col < pivcol [IN]))
+           {
+               /* best column in front, so far */
+               pivcol [IN] = col ;
+               cdeg_in = deg ;
+               jcand [IN] = j ;
+           }
+       }
+       else
+       {
+           if (deg < cdeg_out || (deg == cdeg_out && col < pivcol [OUT]))
+           {
+               /* best column not in front, so far */
+               pivcol [OUT] = col ;
+               cdeg_out = deg ;
+               jcand [OUT] = j ;
+           }
+       }
+    }
+
+    DEBUG2 (("Pivcol in "ID" out "ID"\n", pivcol [IN], pivcol [OUT])) ;
+    ASSERT ((pivcol [IN] >= 0 && pivcol [IN] < n_col)
+       || (pivcol [OUT] >= 0 && pivcol [OUT] < n_col)) ;
+
+    cdeg_in = EMPTY ;
+    cdeg_out = EMPTY ;
+
+    /* ---------------------------------------------------------------------- */
+    /* construct candidate column in front, and search for pivot rows */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    /* check Frpos */
+    DEBUG4 (("Prior to col update: fnrows "ID" col "ID" maxcdeg "ID"\n",
+           fnrows, pivcol [IN], max_cdeg)) ;
+    for (i = 0 ; i < fnrows ; i++)
+    {
+       row = Frows [i] ;
+       DEBUG4 (("  row: "ID"\n", row)) ;
+       ASSERT (row >= 0 && row < n_row) ;
+       ASSERT (Frpos [row] == i) ;
+    }
+    DEBUG4 (("All:\n")) ;
+    if (UMF_debug > 0 || n_row < 1000)
+    {
+       Int cnt = fnrows ;
+       for (row = 0 ; row < n_row ; row++)
+       {
+           if (Frpos [row] == EMPTY)
+           {
+               cnt++ ;
+           }
+           else
+           {
+               DEBUG4 (("  row: "ID" pos "ID"\n", row, Frpos [row])) ;
+           }
+       }
+       ASSERT (cnt == n_row) ;
+    }
+#endif
+
+    if (pivcol [IN] != EMPTY)
+    {
+
+#ifndef NDEBUG
+       DEBUG2 (("col[IN] column "ID" in front at position = "ID"\n",
+               pivcol [IN], Fcpos [pivcol [IN]])) ;
+       UMF_dump_rowcol (1, Numeric, Work, pivcol [IN], !Symbolic->fixQ) ;
+#endif
+
+       /* the only way we can have a pivcol[IN] is if the front is not empty */
+       ASSERT (fnrows > 0 && fncols > 0) ;
+
+       DEBUG4 (("Update pivot column:\n")) ;
+       Fs  = Fcblock  +  Fcpos [pivcol [IN]] ;
+       Fu  = Fublock  + (Fcpos [pivcol [IN]] / fnr_curr) ;
+       Flu = Flublock + fnpiv * nb ;
+
+       /* ------------------------------------------------------------------ */
+       /* copy the pivot column from the U block into the LU block */
+       /* ------------------------------------------------------------------ */
+
+       /* This copy is permanent if the pivcol [IN] is chosen. */
+       for (i = 0 ; i < fnpiv ; i++)
+       {
+           Flu [i] = Fu [i*fnc_curr] ;
+       }
+
+       /* ------------------------------------------------------------------ */
+       /* update the pivot column in the LU block using a triangular solve */
+       /* ------------------------------------------------------------------ */
+
+       /* This work will be discarded if the pivcol [OUT] is chosen instead.
+        * It is permanent if the pivcol [IN] is chosen. */
+
+       if (fnpiv > 1)
+       {
+           /* solve Lx=b, where b = U (:,k), stored in the LU block */
+
+#ifdef USE_NO_BLAS
+
+           /* no BLAS available - use plain C code instead */
+           Entry *Flub = Flublock ;
+           for (j = 0 ; j < fnpiv ; j++)
+           {
+               Entry Fuj = Flu [j] ;
+#pragma ivdep
+               for (i = j+1 ; i < fnpiv ; i++)
+               {
+                   /* Flu [i] -= Flublock [i + j*nb] * Flu [j] ; */
+                   MULT_SUB (Flu [i], Flub [i], Fuj) ;
+               }
+               Flub += nb ;
+           }
+
+#else
+           BLAS_TRSV (fnpiv, Flublock, Flu, nb) ;
+#endif
+
+       }
+
+       /* ------------------------------------------------------------------ */
+       /* copy the pivot column from the C block into Wy */
+       /* ------------------------------------------------------------------ */
+
+       for (i = 0 ; i < fnrows ; i++)
+       {
+           Wy [i] = Fs [i] ;
+       }
+
+       /* ------------------------------------------------------------------ */
+       /* update the pivot column of L using a matrix-vector multiply */
+       /* ------------------------------------------------------------------ */
+
+       /* this work will be discarded if the pivcol [OUT] is chosen instead */
+
+#ifdef USE_NO_BLAS
+       /* no BLAS available - use plain C code instead */
+       for (j = 0 ; j < fnpiv ; j++)
+       {
+           Entry Fuj, *Flub = Flblock + j * fnr_curr ;
+           Fuj = Flu [j] ;
+           if (IS_NONZERO (Fuj))
+           {
+#pragma ivdep
+               for (i = 0 ; i < fnrows ; i++)
+               {
+                   /* Wy [i] -= Flblock [i+j*fnr_curr] * Fuj ; */
+                   MULT_SUB (Wy [i], Flub [i], Fuj) ;
+               }
+           }
+           /* Flblock += fnr_curr ; */
+       }
+#else
+       /* Using 1-based notation:
+        * Wy (1:fnrows) -= Flblock (1:fnrows,1:fnpiv) * Flu (1:fnpiv) */
+       BLAS_GEMV (fnrows, fnpiv, Flblock, Flu, Wy, fnr_curr) ;
+#endif
+
+       /* ------------------------------------------------------------------ */
+
+#ifndef NDEBUG
+       DEBUG2 (("Wy after update: fnrows="ID"\n", fnrows)) ;
+       DEBUG4 ((" fnpiv="ID" \n", fnpiv)) ;
+       for (i = 0 ; i < fnrows ; i++)
+       {
+           DEBUG4 ((ID" "ID" "ID, i, Frows [i], Frpos [Frows [i]])) ;
+           EDEBUG4 (Wy [i]) ;
+           DEBUG4 (("\n")) ;
+       }
+#endif
+
+       /* ------------------------------------------------------------------ */
+       /* construct the candidate column */
+       /* ------------------------------------------------------------------ */
+
+       cdeg_in = fnrows ;
+
+#ifndef NDEBUG
+       /* check Frpos */
+       DEBUG4 (("After col update: fnrows "ID" col "ID" maxcdeg "ID"\n",
+               fnrows, pivcol [IN], max_cdeg)) ;
+       for (i = 0 ; i < fnrows ; i++)
+       {
+           row = Frows [i] ;
+           DEBUG4 (("  row: "ID"\n", row)) ;
+           ASSERT (row >= 0 && row < n_row) ;
+           ASSERT (Frpos [row] == i) ;
+       }
+       DEBUG4 (("All:\n")) ;
+       if (UMF_debug > 0 || n_row < 1000)
+       {
+           Int cnt = fnrows ;
+           for (row = 0 ; row < n_row ; row++)
+           {
+               if (Frpos [row] == EMPTY)
+               {
+                   cnt++ ;
+               }
+               else
+               {
+                   DEBUG4 (("  row: "ID" pos "ID"\n", row, Frpos [row])) ;
+               }
+           }
+           ASSERT (cnt == n_row) ;
+       }
+#endif
+
+#ifndef NDEBUG
+       /* check Frpos */
+       DEBUG4 (("COL ASSEMBLE: cdeg "ID"\nREDUCE COL in "ID" max_cdeg "ID"\n",
+               cdeg_in, pivcol [IN], max_cdeg)) ;
+       for (i = 0 ; i < cdeg_in ; i++)
+       {
+           row = Frows [i] ;
+           ASSERT (row >= 0 && row < n_row) ;
+           ASSERT (Frpos [row] == i) ;
+       }
+       if (UMF_debug > 0 || n_row < 1000)
+       {
+           Int cnt = cdeg_in ;
+           for (row = 0 ; row < n_row ; row++)
+           {
+               if (Frpos [row] == EMPTY) cnt++ ;
+           }
+           ASSERT (cnt == n_row) ;
+       }
+#endif
+
+       /* assemble column into Wy */
+
+       ASSERT (pivcol [IN] >= 0 && pivcol [IN] < n_col) ;
+       ASSERT (NON_PIVOTAL_COL (pivcol [IN])) ;
+
+       tpi = Col_tuples [pivcol [IN]] ;
+       if (tpi)
+       {
+           tp = (Tuple *) (Memory + tpi) ;
+           tp1 = tp ;
+           tp2 = tp ;
+           tpend = tp + Col_tlen [pivcol [IN]] ;
+           for ( ; tp < tpend ; tp++)
+           {
+               e = tp->e ;
+               ASSERT (e > 0 && e <= Work->nel) ;
+               if (!E [e]) continue ;  /* element already deallocated */
+               f = tp->f ;
+               p = Memory + E [e] ;
+               ep = (Element *) p ;
+               p += UNITS (Element, 1) ;
+               Cols = (Int *) p ;
+               if (Cols [f] == EMPTY) continue ; /* column already assembled */
+               ASSERT (pivcol [IN] == Cols [f]) ;
+
+               Rows = Cols + ep->ncols ;
+               nrows = ep->nrows ;
+               p += UNITS (Int, ep->ncols + nrows) ;
+               C = ((Entry *) p) + f * nrows ;
+
+               for (i = 0 ; i < nrows ; i++)
+               {
+                   row = Rows [i] ;
+                   if (row >= 0) /* skip this if already gone from element */
+                   {
+                       ASSERT (row < n_row) ;
+                       pos = Frpos [row] ;
+                       if (pos < 0)
+                       {
+                           /* new entry in the pattern - save Frpos */
+                           ASSERT (cdeg_in < n_row) ;
+                           if (cdeg_in >= max_cdeg)
+                           {
+                               /* :: pattern change (cdeg in failure) :: */
+                               DEBUGm4 (("cdeg_in failure\n")) ;
+                               return (UMFPACK_ERROR_different_pattern) ;
+                           }
+                           Frpos [row] = cdeg_in ;
+                           Frows [cdeg_in] = row ;
+                           Wy [cdeg_in++] = C [i] ;
+                       }
+                       else
+                       {
+                           /* entry already in pattern - sum values in Wy */
+                           /* Wy [pos] += C [i] ; */
+                           ASSERT (pos < max_cdeg) ;
+                           ASSEMBLE (Wy [pos], C [i]) ;
+                       }
+                   }
+               }
+               *tp2++ = *tp ;  /* leave the tuple in the list */
+           }
+           Col_tlen [pivcol [IN]] = tp2 - tp1 ;
+       }
+
+       /* ------------------------------------------------------------------ */
+
+#ifndef NDEBUG
+       /* check Frpos again */
+       DEBUG4 (("COL DONE: cdeg "ID"\nREDUCE COL in "ID" max_cdeg "ID"\n",
+               cdeg_in, pivcol [IN], max_cdeg)) ;
+       for (i = 0 ; i < cdeg_in ; i++)
+       {
+           row = Frows [i] ;
+           ASSERT (row >= 0 && row < n_row) ;
+           ASSERT (Frpos [row] == i) ;
+       }
+       if (UMF_debug > 0 || n_row < 1000)
+       {
+           Int cnt = cdeg_in ;
+           for (row = 0 ; row < n_row ; row++)
+           {
+               if (Frpos [row] == EMPTY) cnt++ ;
+           }
+           ASSERT (cnt == n_row) ;
+       }
+#endif
+
+#ifndef NDEBUG
+       DEBUG4 (("Reduced column: cdeg in  "ID" fnrows_max "ID"\n",
+           cdeg_in, Work->fnrows_max)) ;
+       for (i = 0 ; i < cdeg_in ; i++)
+       {
+           DEBUG4 ((" "ID" "ID" "ID, i, Frows [i], Frpos [Frows [i]])) ;
+           EDEBUG4 (Wy [i]) ;
+           DEBUG4 (("\n")) ;
+           ASSERT (i == Frpos [Frows [i]]) ;
+       }
+       ASSERT (cdeg_in <= Work->fnrows_max) ;
+#endif
+
+       /* ------------------------------------------------------------------ */
+       /* cdeg_in is now the exact degree of this column */
+       /* ------------------------------------------------------------------ */
+
+       nr_in = cdeg_in - fnrows ;
+
+       /* since there are no 0-by-x fronts, if there is a pivcol [IN] the */
+       /* front must have at least one row. */
+       ASSERT (cdeg_in > 0) ;
+
+       /* new degree of pivcol [IN], excluding current front is nr_in */
+       /* column expands by nr_in rows */
+
+       /* ------------------------------------------------------------------ */
+       /* search for two candidate pivot rows */
+       /* ------------------------------------------------------------------ */
+
+       /* for the IN_IN pivot row (if any), */
+       /* extend the pattern in place, using Fcols */
+       status = UMF_row_search (Numeric, Work, Symbolic,
+           fnrows, cdeg_in, Frows, Frpos,   /* pattern of column to search */
+           pivrow [IN], rdeg [IN], Fcols, Wio, nothing, Wy,
+           pivcol [IN], freebie) ;
+       ASSERT (!freebie [IN] && !freebie [OUT]) ;
+
+       /* ------------------------------------------------------------------ */
+       /* fatal error if matrix pattern has changed since symbolic analysis */
+       /* ------------------------------------------------------------------ */
+
+       if (status == UMFPACK_ERROR_different_pattern)
+       {
+           /* :: pattern change (row search IN failure) :: */
+           DEBUGm4 (("row search IN failure\n")) ;
+           return (UMFPACK_ERROR_different_pattern) ;
+       }
+
+       /* ------------------------------------------------------------------ */
+       /* we now must have a structural pivot */
+       /* ------------------------------------------------------------------ */
+
+       /* Since the pivcol[IN] exists, there must be at least one row in the */
+       /* current frontal matrix, and so we must have found a structural */
+       /* pivot.  The numerical value might be zero, of course. */
+
+       ASSERT (status != UMFPACK_WARNING_singular_matrix) ;
+
+       /* ------------------------------------------------------------------ */
+       /* evaluate IN_IN option */
+       /* ------------------------------------------------------------------ */
+
+       if (pivrow [IN][IN] != EMPTY)
+       {
+           /* The current front would become an (implicit) LUson.
+            * Both candidate pivot row and column are in the current front.
+            * Cost is how much the current front would expand */
+
+           /* pivrow[IN][IN] candidates are not found via row merge search */
+
+           ASSERT (fnrows >= 0 && fncols >= 0) ;
+
+           ASSERT (cdeg_in > 0) ;
+           nc = rdeg [IN][IN] - fncols ;
+
+           thiscost =
+               /* each column in front (except pivot column) grows by nr_in: */
+               (nr_in * (fncols - 1)) +
+               /* new columns not in old front: */
+               (nc * (cdeg_in - 1)) ;
+
+           /* no extra cost to relaxed amalgamation */
+
+           ASSERT (fnrows + nr_in == cdeg_in) ;
+           ASSERT (fncols + nc == rdeg [IN][IN]) ;
+
+           /* size of relaxed front (after pivot row column removed): */
+           fnrows_new [IN][IN] = (fnrows-1) + nr_in ;
+           fncols_new [IN][IN] = (fncols-1) + nc ;
+           /* relaxed_front = fnrows_new [IN][IN] * fncols_new [IN][IN] ; */
+
+           do_extend = TRUE ;
+
+           DEBUG2 (("Evaluating option IN-IN:\n")) ;
+           DEBUG2 (("Work->fnzeros "ID" fnpiv "ID" nr_in "ID" nc "ID"\n",
+               Work->fnzeros, fnpiv, nr_in, nc)) ;
+           DEBUG2 (("fncols "ID" fnrows "ID"\n", fncols, fnrows)) ;
+
+           /* determine if BLAS-3 update should be applied before extending. */
+           /* update if too many zero entries accumulate in the LU block */
+           fnzeros = Work->fnzeros + fnpiv * (nr_in + nc) ;
+
+           DEBUG2 (("fnzeros "ID"\n", fnzeros)) ;
+
+           new_LUsize = (fnpiv+1) * (fnrows + nr_in + fncols + nc) ;
+
+           DEBUG2 (("new_LUsize "ID"\n", new_LUsize)) ;
+
+           /* There are fnpiv pivots currently in the front.  This one
+            * will be the (fnpiv+1)st pivot, if it is extended. */
+
+           /* RELAX2 parameter uses a double relop, but ignore NaN case: */
+           do_update = fnpiv > 0 &&
+               (((double) fnzeros) / ((double) new_LUsize)) > RELAX2 ;
+
+           DEBUG2 (("do_update "ID"\n", do_update))
+
+           DEBUG2 (("option IN  IN : nr "ID" nc "ID" cost "ID"(0) relax "ID
+               "\n", nr_in, nc, thiscost, do_extend)) ;
+
+           /* this is the best option seen so far */
+           Work->pivot_case = IN_IN ;
+           bestcost = thiscost ;
+
+           /* do the amalgamation and extend the front */
+           Work->do_extend = do_extend ;
+           Work->do_update = do_update ;
+           new_fnzeros = fnzeros ;
+
+       }
+
+       /* ------------------------------------------------------------------ */
+       /* evaluate IN_OUT option */
+       /* ------------------------------------------------------------------ */
+
+       if (pivrow [IN][OUT] != EMPTY)
+       {
+           /* The current front would become a Uson of the new front.
+            * Candidate pivot column is in the current front, but the
+            * candidate pivot row is not. */
+
+           ASSERT (fnrows >= 0 && fncols > 0) ;
+           ASSERT (cdeg_in > 0) ;
+
+           /* must be at least one row outside the front */
+           /* (the pivrow [IN][OUT] itself) */
+           ASSERT (nr_in >= 1) ;
+
+           /* count columns not in current front */
+           nc = 0 ;
+#ifndef NDEBUG
+           debug_ok = FALSE ;
+#endif
+           for (i = 0 ; i < rdeg [IN][OUT] ; i++)
+           {
+               col = Wio [i] ;
+               DEBUG4 (("counting col "ID" Fcpos[] = "ID"\n", col,
+                   Fcpos [col])) ;
+               ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ;
+               if (Fcpos [col] < 0) nc++ ;
+#ifndef NDEBUG
+               /* we must see the pivot column somewhere */
+               if (col == pivcol [IN])
+               {
+                   ASSERT (Fcpos [col] >= 0) ;
+                   debug_ok = TRUE ;
+               }
+#endif
+           }
+           ASSERT (debug_ok) ;
+
+           thiscost =
+               /* each row in front grows by nc: */
+               (nc * fnrows) +
+               /* new rows not affected by front: */
+               ((nr_in-1) * (rdeg [IN][OUT]-1)) ;
+
+           /* check the cost of relaxed IN_OUT amalgamation */
+
+           extra_cols = ((fncols-1) + nc ) - (rdeg [IN][OUT] - 1) ;
+           ASSERT (extra_cols >= 0) ;
+           ASSERT (fncols + nc == extra_cols + rdeg [IN][OUT]) ;
+           extra_zeros = (nr_in-1) * extra_cols ;      /* symbolic fill-in */
+
+           ASSERT (fnrows + nr_in == cdeg_in) ;
+           ASSERT (fncols + nc == rdeg [IN][OUT] + extra_cols) ;
+
+           /* size of relaxed front (after pivot column removed): */
+           fnrows_new [IN][OUT] = fnrows + (nr_in-1) ;
+           fncols_new [IN][OUT] = (fncols-1) + nc ;
+           relaxed_front = fnrows_new [IN][OUT] * fncols_new [IN][OUT] ;
+
+           /* do relaxed amalgamation if the extra zeros are no more */
+           /* than a fraction (default 0.25) of the relaxed front */
+           /* if relax = 0: no extra zeros allowed */
+           /* if relax = +inf: always amalgamate */
+
+           /* relax parameter uses a double relop, but ignore NaN case: */
+           if (extra_zeros == 0)
+           {
+               do_extend = TRUE ;
+           }
+           else
+           {
+               do_extend = ((double) extra_zeros) <
+                  (relax1 * (double) relaxed_front) ;
+           }
+
+           if (do_extend)
+           {
+               /* count the cost of relaxed amalgamation */
+               thiscost += extra_zeros ;
+
+               DEBUG2 (("Evaluating option IN-OUT:\n")) ;
+               DEBUG2 (("Work->fnzeros "ID" fnpiv "ID" nr_in "ID" nc "ID"\n",
+                   Work->fnzeros, fnpiv, nr_in, nc)) ;
+               DEBUG2 (("fncols "ID" fnrows "ID"\n", fncols, fnrows)) ;
+
+               /* determine if BLAS-3 update to be applied before extending. */
+               /* update if too many zero entries accumulate in the LU block */
+               fnzeros = Work->fnzeros + fnpiv * (nr_in + nc) ;
+
+               DEBUG2 (("fnzeros "ID"\n", fnzeros)) ;
+
+               new_LUsize = (fnpiv+1) * (fnrows + nr_in + fncols + nc) ;
+
+               DEBUG2 (("new_LUsize "ID"\n", new_LUsize)) ;
+
+               /* RELAX3 parameter uses a double relop, ignore NaN case: */
+               do_update = fnpiv > 0 &&
+                   (((double) fnzeros) / ((double) new_LUsize)) > RELAX3 ;
+               DEBUG2 (("do_update "ID"\n", do_update))
+
+           }
+           else
+           {
+               /* the current front would not be extended */
+               do_update = fnpiv > 0 ;
+               fnzeros = 0 ;
+               DEBUG2 (("IN-OUT do_update forced true: "ID"\n", do_update)) ;
+
+               /* The new front would be just big enough to hold the new
+                * pivot row and column. */
+               fnrows_new [IN][OUT] = cdeg_in - 1 ;
+               fncols_new [IN][OUT] = rdeg [IN][OUT] - 1 ;
+
+           }
+
+           DEBUG2 (("option IN  OUT: nr "ID" nc "ID" cost "ID"("ID") relax "ID
+               "\n", nr_in, nc, thiscost, extra_zeros, do_extend)) ;
+
+           if (bestcost == EMPTY || thiscost < bestcost)
+           {
+               /* this is the best option seen so far */
+               Work->pivot_case = IN_OUT ;
+               bestcost = thiscost ;
+               Work->do_extend = do_extend ;
+               Work->do_update = do_update ;
+               new_fnzeros = fnzeros ;
+           }
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* construct candidate column not in front, and search for pivot rows */
+    /* ---------------------------------------------------------------------- */
+
+    search_pivcol_out = (bestcost != 0 && pivcol [OUT] != EMPTY) ;
+    if (Symbolic->prefer_diagonal)
+    {
+       search_pivcol_out = search_pivcol_out && (pivrow [IN][IN] == EMPTY) ;
+    }
+
+    if (search_pivcol_out)
+    {
+
+#ifndef NDEBUG
+       DEBUG2 (("out_col column "ID" NOT in front at position = "ID"\n",
+               pivcol [OUT], Fcpos [pivcol [OUT]])) ;
+       UMF_dump_rowcol (1, Numeric, Work, pivcol [OUT], !Symbolic->fixQ) ;
+       DEBUG2 (("fncols "ID" fncols_max "ID"\n", fncols, Work->fncols_max)) ;
+       ASSERT (fncols < Work->fncols_max) ;
+#endif
+
+       /* Use Wx as temporary workspace to construct the pivcol [OUT] */
+
+
+       /* ------------------------------------------------------------------ */
+       /* construct the candidate column (currently not in the front) */
+       /* ------------------------------------------------------------------ */
+
+       /* Construct the column in Wx, Wm, using Wp for the positions: */
+       /* Wm [0..cdeg_out-1]   list of row indices in the column */
+       /* Wx [0..cdeg_out-1]   list of corresponding numerical values */
+       /* Wp [0..n-1] starts as all negative, and ends that way too. */
+
+       cdeg_out = 0 ;
+
+#ifndef NDEBUG
+       /* check Wp */
+       DEBUG4 (("COL ASSEMBLE: cdeg 0\nREDUCE COL out "ID"\n", pivcol [OUT])) ;
+       if (UMF_debug > 0 || MAX (n_row, n_col) < 1000)
+       {
+           for (i = 0 ; i < MAX (n_row, n_col) ; i++)
+           {
+               ASSERT (Wp [i] < 0) ;
+           }
+       }
+       DEBUG4 (("max_cdeg: "ID"\n", max_cdeg)) ;
+#endif
+
+       ASSERT (pivcol [OUT] >= 0 && pivcol [OUT] < n_col) ;
+       ASSERT (NON_PIVOTAL_COL (pivcol [OUT])) ;
+
+       tpi = Col_tuples [pivcol [OUT]] ;
+       if (tpi)
+       {
+           tp = (Tuple *) (Memory + tpi) ;
+           tp1 = tp ;
+           tp2 = tp ;
+           tpend = tp + Col_tlen [pivcol [OUT]] ;
+           for ( ; tp < tpend ; tp++)
+           {
+               e = tp->e ;
+               ASSERT (e > 0 && e <= Work->nel) ;
+               if (!E [e]) continue ;  /* element already deallocated */
+               f = tp->f ;
+               p = Memory + E [e] ;
+               ep = (Element *) p ;
+               p += UNITS (Element, 1) ;
+               Cols = (Int *) p ;
+               if (Cols [f] == EMPTY) continue ; /* column already assembled */
+               ASSERT (pivcol [OUT] == Cols [f]) ;
+
+               Rows = Cols + ep->ncols ;
+               nrows = ep->nrows ;
+               p += UNITS (Int, ep->ncols + nrows) ;
+               C = ((Entry *) p) + f * nrows ;
+
+               for (i = 0 ; i < nrows ; i++)
+               {
+                   row = Rows [i] ;
+                   if (row >= 0) /* skip this if already gone from element */
+                   {
+                       ASSERT (row < n_row) ;
+                       pos = Wp [row] ;
+                       if (pos < 0)
+                       {
+                           /* new entry in the pattern - save Wp */
+                           ASSERT (cdeg_out < n_row) ;
+                           if (cdeg_out >= max_cdeg)
+                           {
+                               /* :: pattern change (cdeg out failure) :: */
+                               DEBUGm4 (("cdeg out failure\n")) ;
+                               return (UMFPACK_ERROR_different_pattern) ;
+                           }
+                           Wp [row] = cdeg_out ;
+                           Wm [cdeg_out] = row ;
+                           Wx [cdeg_out++] = C [i] ;
+                       }
+                       else
+                       {
+                           /* entry already in pattern - sum the values */
+                           /* Wx [pos] += C [i] ; */
+                           ASSEMBLE (Wx [pos], C [i]) ;
+                       }
+                   }
+               }
+               *tp2++ = *tp ;  /* leave the tuple in the list */
+           }
+           Col_tlen [pivcol [OUT]] = tp2 - tp1 ;
+       }
+
+       /* ------------------------------------------------------------------ */
+
+#ifndef NDEBUG
+       DEBUG4 (("Reduced column: cdeg out "ID"\n", cdeg_out)) ;
+       for (i = 0 ; i < cdeg_out ; i++)
+       {
+           DEBUG4 ((" "ID" "ID" "ID, i, Wm [i], Wp [Wm [i]])) ;
+           EDEBUG4 (Wx [i]) ;
+           DEBUG4 (("\n")) ;
+           ASSERT (i == Wp [Wm [i]]) ;
+       }
+#endif
+
+       /* ------------------------------------------------------------------ */
+       /* new degree of pivcol [OUT] is cdeg_out */
+       /* ------------------------------------------------------------------ */
+
+       /* search for two candidate pivot rows */
+       status = UMF_row_search (Numeric, Work, Symbolic,
+           0, cdeg_out, Wm, Wp, /* pattern of column to search */
+           pivrow [OUT], rdeg [OUT], Woi, Woo, pivrow [IN], Wx,
+           pivcol [OUT], freebie) ;
+
+       /* ------------------------------------------------------------------ */
+       /* fatal error if matrix pattern has changed since symbolic analysis */
+       /* ------------------------------------------------------------------ */
+
+       if (status == UMFPACK_ERROR_different_pattern)
+       {
+           /* :: pattern change detected in umf_local_search :: */
+           return (UMFPACK_ERROR_different_pattern) ;
+       }
+
+       /* ------------------------------------------------------------------ */
+       /* Clear Wp */
+       /* ------------------------------------------------------------------ */
+
+       for (i = 0 ; i < cdeg_out ; i++)
+       {
+           Wp [Wm [i]] = EMPTY ;       /* clear Wp */
+       }
+
+       /* ------------------------------------------------------------------ */
+       /* check for rectangular, singular matrix */
+       /* ------------------------------------------------------------------ */
+
+       if (status == UMFPACK_WARNING_singular_matrix)
+       {
+           /* Pivot column is empty, and row-merge set is empty too.  The
+            * matrix is structurally singular.  The current frontal matrix must
+            * be empty, too.  It it weren't, and pivcol [OUT] exists, then
+            * there would be at least one row that could be selected.  Since
+            * the current front is empty, pivcol [IN] must also be EMPTY.
+            */
+
+           DEBUGm4 (("Note: pivcol [OUT]: "ID" discard\n", pivcol [OUT])) ;
+           ASSERT ((Work->fnrows == 0 && Work->fncols == 0)) ;
+           ASSERT (pivcol [IN] == EMPTY) ;
+
+           /* remove the failed pivcol [OUT] from candidate set */
+           ASSERT (pivcol [OUT] == Work->Candidates [jcand [OUT]]) ;
+           remove_candidate (jcand [OUT], Work, Symbolic) ;
+           Work->ndiscard++ ;
+
+           /* delete all of the tuples, and all contributions to this column */
+           DEBUG1 (("Prune tuples of dead outcol: "ID"\n", pivcol [OUT])) ;
+           Col_tlen [pivcol [OUT]] = 0 ;
+           UMF_mem_free_tail_block (Numeric, Col_tuples [pivcol [OUT]]) ;
+           Col_tuples [pivcol [OUT]] = 0 ;
+
+           /* no pivot found at all */
+           return (UMFPACK_WARNING_singular_matrix) ;
+       }
+
+       /* ------------------------------------------------------------------ */
+
+       if (freebie [IN])
+       {
+           /* the "in" row is the same as the "in" row for the "in" column */
+           Woi = Fcols ;
+           rdeg [OUT][IN] = rdeg [IN][IN] ;
+           DEBUG4 (("Freebie in, row "ID"\n", pivrow [IN][IN])) ;
+       }
+
+       if (freebie [OUT])
+       {
+           /* the "out" row is the same as the "out" row for the "in" column */
+           Woo = Wio ;
+           rdeg [OUT][OUT] = rdeg [IN][OUT] ;
+           DEBUG4 (("Freebie out, row "ID"\n", pivrow [IN][OUT])) ;
+       }
+
+       /* ------------------------------------------------------------------ */
+       /* evaluate OUT_IN option */
+       /* ------------------------------------------------------------------ */
+
+       if (pivrow [OUT][IN] != EMPTY)
+       {
+           /* The current front would become an Lson of the new front.
+            * The candidate pivot row is in the current front, but the
+            * candidate pivot column is not. */
+
+           ASSERT (fnrows > 0 && fncols >= 0) ;
+
+           did_rowmerge = (cdeg_out == 0) ;
+           if (did_rowmerge)
+           {
+               /* pivrow [OUT][IN] was found via row merge search */
+               /* it is not (yet) in the pivot column pattern (add it now) */
+               DEBUGm4 (("did row merge OUT col, IN row\n")) ;
+               Wm [0] = pivrow [OUT][IN] ;
+               CLEAR (Wx [0]) ;
+               cdeg_out = 1 ;
+               ASSERT (nr_out == EMPTY) ;
+           }
+
+           nc = rdeg [OUT][IN] - fncols ;
+           ASSERT (nc >= 1) ;
+
+           /* count rows not in current front */
+           nr_out = 0 ;
+#ifndef NDEBUG
+           debug_ok = FALSE ;
+#endif
+           for (i = 0 ; i < cdeg_out ; i++)
+           {
+               row = Wm [i] ;
+               ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ;
+               if (Frpos [row] < 0 || Frpos [row] >= fnrows) nr_out++ ;
+#ifndef NDEBUG
+               /* we must see the pivot row somewhere */
+               if (row == pivrow [OUT][IN])
+               {
+                   ASSERT (Frpos [row] >= 0) ;
+                   debug_ok = TRUE ;
+               }
+#endif
+           }
+           ASSERT (debug_ok) ;
+
+           thiscost =
+               /* each column in front grows by nr_out: */
+               (nr_out * fncols) +
+               /* new cols not affected by front: */
+               ((nc-1) * (cdeg_out-1)) ;
+
+           /* check the cost of relaxed OUT_IN amalgamation */
+
+           extra_rows = ((fnrows-1) + nr_out) - (cdeg_out - 1) ;
+           ASSERT (extra_rows >= 0) ;
+           ASSERT (fnrows + nr_out == extra_rows + cdeg_out) ;
+           extra_zeros = (nc-1) * extra_rows ; /* symbolic fill-in */
+
+           ASSERT (fnrows + nr_out == cdeg_out + extra_rows) ;
+           ASSERT (fncols + nc == rdeg [OUT][IN]) ;
+
+           /* size of relaxed front (after pivot row removed): */
+           fnrows_new [OUT][IN] = (fnrows-1) + nr_out ;
+           fncols_new [OUT][IN] = fncols + (nc-1) ;
+           relaxed_front = fnrows_new [OUT][IN] * fncols_new [OUT][IN] ;
+
+           /* do relaxed amalgamation if the extra zeros are no more */
+           /* than a fraction (default 0.25) of the relaxed front */
+           /* if relax = 0: no extra zeros allowed */
+           /* if relax = +inf: always amalgamate */
+           if (did_rowmerge)
+           {
+               do_extend = FALSE ;
+           }
+           else
+           {
+               /* relax parameter uses a double relop, but ignore NaN case: */
+               if (extra_zeros == 0)
+               {
+                   do_extend = TRUE ;
+               }
+               else
+               {
+                   do_extend = ((double) extra_zeros) <
+                      (relax1 * (double) relaxed_front) ;
+               }
+           }
+
+           if (do_extend)
+           {
+               /* count the cost of relaxed amalgamation */
+               thiscost += extra_zeros ;
+
+               DEBUG2 (("Evaluating option OUT-IN:\n")) ;
+               DEBUG2 ((" Work->fnzeros "ID" fnpiv "ID" nr_out "ID" nc "ID"\n",
+               Work->fnzeros, fnpiv, nr_out, nc)) ;
+               DEBUG2 (("fncols "ID" fnrows "ID"\n", fncols, fnrows)) ;
+
+               /* determine if BLAS-3 update to be applied before extending. */
+               /* update if too many zero entries accumulate in the LU block */
+               fnzeros = Work->fnzeros + fnpiv * (nr_out + nc) ;
+
+               DEBUG2 (("fnzeros "ID"\n", fnzeros)) ;
+
+               new_LUsize = (fnpiv+1) * (fnrows + nr_out + fncols + nc) ;
+
+               DEBUG2 (("new_LUsize "ID"\n", new_LUsize)) ;
+
+               /* RELAX3 parameter uses a double relop, ignore NaN case: */
+               do_update = fnpiv > 0 &&
+                   (((double) fnzeros) / ((double) new_LUsize)) > RELAX3 ;
+               DEBUG2 (("do_update "ID"\n", do_update))
+           }
+           else
+           {
+               /* the current front would not be extended */
+               do_update = fnpiv > 0 ;
+               fnzeros = 0 ;
+               DEBUG2 (("OUT-IN do_update forced true: "ID"\n", do_update)) ;
+
+               /* The new front would be just big enough to hold the new
+                * pivot row and column. */
+               fnrows_new [OUT][IN] = cdeg_out - 1 ;
+               fncols_new [OUT][IN] = rdeg [OUT][IN] - 1 ;
+           }
+
+           DEBUG2 (("option OUT IN : nr "ID" nc "ID" cost "ID"("ID") relax "ID
+               "\n", nr_out, nc, thiscost, extra_zeros, do_extend)) ;
+
+           if (bestcost == EMPTY || thiscost < bestcost)
+           {
+               /* this is the best option seen so far */
+               Work->pivot_case = OUT_IN ;
+               bestcost = thiscost ;
+               Work->do_extend = do_extend ;
+               Work->do_update = do_update ;
+               new_fnzeros = fnzeros ;
+           }
+       }
+
+       /* ------------------------------------------------------------------ */
+       /* evaluate OUT_OUT option */
+       /* ------------------------------------------------------------------ */
+
+       if (pivrow [OUT][OUT] != EMPTY)
+       {
+           /* Neither the candidate pivot row nor the candidate pivot column
+            * are in the current front. */
+
+           ASSERT (fnrows >= 0 && fncols >= 0) ;
+
+           did_rowmerge = (cdeg_out == 0) ;
+           if (did_rowmerge)
+           {
+               /* pivrow [OUT][OUT] was found via row merge search */
+               /* it is not (yet) in the pivot column pattern (add it now) */
+               DEBUGm4 (("did row merge OUT col, OUT row\n")) ;
+               Wm [0] = pivrow [OUT][OUT] ;
+               CLEAR (Wx [0]) ;
+               cdeg_out = 1 ;
+               ASSERT (nr_out == EMPTY) ;
+               nr_out = 1 ;
+           }
+
+           if (fnrows == 0 && fncols == 0)
+           {
+               /* the current front is completely empty */
+               ASSERT (fnpiv == 0) ;
+               nc = rdeg [OUT][OUT] ;
+               extra_cols = 0 ;
+               nr_out = cdeg_out ;
+               extra_rows = 0 ;
+               extra_zeros = 0 ;
+
+               thiscost = (nc-1) * (cdeg_out-1) ; /* new columns only */
+
+               /* size of new front: */
+               fnrows_new [OUT][OUT] = nr_out-1 ;
+               fncols_new [OUT][OUT] = nc-1 ;
+               relaxed_front = fnrows_new [OUT][OUT] * fncols_new [OUT][OUT] ;
+           }
+           else
+           {
+
+               /* count rows not in current front */
+               if (nr_out == EMPTY)
+               {
+                   nr_out = 0 ;
+#ifndef NDEBUG
+                   debug_ok = FALSE ;
+#endif
+                   for (i = 0 ; i < cdeg_out ; i++)
+                   {
+                       row = Wm [i] ;
+                       ASSERT (row >= 0 && row < n_row) ;
+                       ASSERT (NON_PIVOTAL_ROW (row)) ;
+                       if (Frpos [row] < 0 || Frpos [row] >= fnrows) nr_out++ ;
+#ifndef NDEBUG
+                       /* we must see the pivot row somewhere */
+                       if (row == pivrow [OUT][OUT])
+                       {
+                           ASSERT (Frpos [row] < 0 || Frpos [row] >= fnrows) ;
+                           debug_ok = TRUE ;
+                       }
+#endif
+                   }
+                   ASSERT (debug_ok) ;
+               }
+
+               /* count columns not in current front */
+               nc = 0 ;
+#ifndef NDEBUG
+               debug_ok = FALSE ;
+#endif
+               for (i = 0 ; i < rdeg [OUT][OUT] ; i++)
+               {
+                   col = Woo [i] ;
+                   ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ;
+                   if (Fcpos [col] < 0) nc++ ;
+#ifndef NDEBUG
+                   /* we must see the pivot column somewhere */
+                   if (col == pivcol [OUT])
+                   {
+                       ASSERT (Fcpos [col] < 0) ;
+                       debug_ok = TRUE ;
+                   }
+#endif
+               }
+               ASSERT (debug_ok) ;
+
+               extra_cols = (fncols + (nc-1)) - (rdeg [OUT][OUT] - 1) ;
+               extra_rows = (fnrows + (nr_out-1)) - (cdeg_out - 1) ;
+               ASSERT (extra_rows >= 0) ;
+               ASSERT (extra_cols >= 0) ;
+               extra_zeros = ((nc-1) * extra_rows) + ((nr_out-1) * extra_cols);
+
+               ASSERT (fnrows + nr_out == cdeg_out + extra_rows) ;
+               ASSERT (fncols + nc == rdeg [OUT][OUT] + extra_cols) ;
+
+               thiscost =
+                   /* new columns: */
+                   ((nc-1) * (cdeg_out-1)) +
+                   /* old columns in front grow by nr_out-1: */
+                   ((nr_out-1) * (fncols - extra_cols)) ;
+
+               /* size of relaxed front: */
+               fnrows_new [OUT][OUT] = fnrows + (nr_out-1) ;
+               fncols_new [OUT][OUT] = fncols + (nc-1) ;
+               relaxed_front = fnrows_new [OUT][OUT] * fncols_new [OUT][OUT] ;
+
+           }
+
+           /* do relaxed amalgamation if the extra zeros are no more */
+           /* than a fraction (default 0.25) of the relaxed front */
+           /* if relax = 0: no extra zeros allowed */
+           /* if relax = +inf: always amalgamate */
+           if (did_rowmerge)
+           {
+               do_extend = FALSE ;
+           }
+           else
+           {
+               /* relax parameter uses a double relop, but ignore NaN case: */
+               if (extra_zeros == 0)
+               {
+                   do_extend = TRUE ;
+               }
+               else
+               {
+                   do_extend = ((double) extra_zeros) <
+                      (relax1 * (double) relaxed_front) ;
+               }
+           }
+
+           if (do_extend)
+           {
+               /* count the cost of relaxed amalgamation */
+               thiscost += extra_zeros ;
+
+               DEBUG2 (("Evaluating option OUT-OUT:\n")) ;
+               DEBUG2 (("Work->fnzeros "ID" fnpiv "ID" nr_out "ID" nc "ID"\n",
+                   Work->fnzeros, fnpiv, nr_out, nc)) ;
+               DEBUG2 (("fncols "ID" fnrows "ID"\n", fncols, fnrows)) ;
+
+               /* determine if BLAS-3 update to be applied before extending. */
+               /* update if too many zero entries accumulate in the LU block */
+               fnzeros = Work->fnzeros + fnpiv * (nr_out + nc) ;
+
+               DEBUG2 (("fnzeros "ID"\n", fnzeros)) ;
+
+               new_LUsize = (fnpiv+1) * (fnrows + nr_out + fncols + nc) ;
+
+               DEBUG2 (("new_LUsize "ID"\n", new_LUsize)) ;
+
+               /* RELAX3 parameter uses a double relop, ignore NaN case: */
+               do_update = fnpiv > 0 &&
+                   (((double) fnzeros) / ((double) new_LUsize)) > RELAX3 ;
+               DEBUG2 (("do_update "ID"\n", do_update))
+           }
+           else
+           {
+               /* the current front would not be extended */
+               do_update = fnpiv > 0 ;
+               fnzeros = 0 ;
+               DEBUG2 (("OUT-OUT do_update forced true: "ID"\n", do_update)) ;
+
+               /* The new front would be just big enough to hold the new
+                * pivot row and column. */
+               fnrows_new [OUT][OUT] = cdeg_out - 1 ;
+               fncols_new [OUT][OUT] = rdeg [OUT][OUT] - 1 ;
+           }
+
+           DEBUG2 (("option OUT OUT: nr "ID" nc "ID" cost "ID"\n",
+               rdeg [OUT][OUT], cdeg_out, thiscost)) ;
+
+           if (bestcost == EMPTY || thiscost < bestcost)
+           {
+               /* this is the best option seen so far */
+               Work->pivot_case = OUT_OUT ;
+               bestcost = thiscost ;
+               Work->do_extend = do_extend ;
+               Work->do_update = do_update ;
+               new_fnzeros = fnzeros ;
+           }
+       }
+    }
+
+    /* At this point, a structural pivot has been found. */
+    /* It may be numerically zero, however. */
+    ASSERT (Work->pivot_case != EMPTY) ;
+    DEBUG2 (("local search, best option "ID", best cost "ID"\n",
+       Work->pivot_case, bestcost)) ;
+
+    /* ====================================================================== */
+    /* Pivot row and column, and extension, now determined */
+    /* ====================================================================== */
+
+    Work->fnzeros = new_fnzeros ;
+
+    /* ---------------------------------------------------------------------- */
+    /* finalize the pivot row and column */
+    /* ---------------------------------------------------------------------- */
+
+    switch (Work->pivot_case)
+    {
+       case IN_IN:
+           DEBUG2 (("IN-IN option selected\n")) ;
+           ASSERT (fnrows > 0 && fncols > 0) ;
+           Work->pivcol_in_front = TRUE ;
+           Work->pivrow_in_front = TRUE ;
+           Work->pivcol = pivcol [IN] ;
+           Work->pivrow = pivrow [IN][IN] ;
+           Work->ccdeg = nr_in ;
+           Work->Wrow = Fcols ;
+           Work->rrdeg = rdeg [IN][IN] ;
+           jj = jcand [IN] ;
+           Work->fnrows_new = fnrows_new [IN][IN] ;
+           Work->fncols_new = fncols_new [IN][IN] ;
+           break ;
+
+       case IN_OUT:
+           DEBUG2 (("IN-OUT option selected\n")) ;
+           ASSERT (fnrows >= 0 && fncols > 0) ;
+           Work->pivcol_in_front = TRUE ;
+           Work->pivrow_in_front = FALSE ;
+           Work->pivcol = pivcol [IN] ;
+           Work->pivrow = pivrow [IN][OUT] ;
+           Work->ccdeg = nr_in ;
+           Work->Wrow = Wio ;
+           Work->rrdeg = rdeg [IN][OUT] ;
+           jj = jcand [IN] ;
+           Work->fnrows_new = fnrows_new [IN][OUT] ;
+           Work->fncols_new = fncols_new [IN][OUT] ;
+           break ;
+
+       case OUT_IN:
+           DEBUG2 (("OUT-IN option selected\n")) ;
+           ASSERT (fnrows > 0 && fncols >= 0) ;
+           Work->pivcol_in_front = FALSE ;
+           Work->pivrow_in_front = TRUE ;
+           Work->pivcol = pivcol [OUT] ;
+           Work->pivrow = pivrow [OUT][IN] ;
+           Work->ccdeg = cdeg_out ;
+           /* Wrow might be equivalenced to Fcols (Freebie in): */
+           Work->Wrow = Woi ;
+           Work->rrdeg = rdeg [OUT][IN] ;
+           /* Work->Wrow[0..fncols-1] is not there.  See Fcols instead */
+           jj = jcand [OUT] ;
+           Work->fnrows_new = fnrows_new [OUT][IN] ;
+           Work->fncols_new = fncols_new [OUT][IN] ;
+           break ;
+
+       case OUT_OUT:
+           DEBUG2 (("OUT-OUT option selected\n")) ;
+           ASSERT (fnrows >= 0 && fncols >= 0) ;
+           Work->pivcol_in_front = FALSE ;
+           Work->pivrow_in_front = FALSE ;
+           Work->pivcol = pivcol [OUT] ;
+           Work->pivrow = pivrow [OUT][OUT] ;
+           Work->ccdeg = cdeg_out ;
+           /* Wrow might be equivalenced to Wio (Freebie out): */
+           Work->Wrow = Woo ;
+           Work->rrdeg = rdeg [OUT][OUT] ;
+           jj = jcand [OUT] ;
+           Work->fnrows_new = fnrows_new [OUT][OUT] ;
+           Work->fncols_new = fncols_new [OUT][OUT] ;
+           break ;
+
+    }
+
+    ASSERT (IMPLIES (fnrows == 0 && fncols == 0, Work->pivot_case == OUT_OUT)) ;
+
+    if (!Work->pivcol_in_front && pivcol [IN] != EMPTY)
+    {
+       /* clear Frpos if pivcol [IN] was searched, but not selected */
+       for (i = fnrows ; i < cdeg_in ; i++)
+       {
+           Frpos [Frows [i]] = EMPTY;
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* Pivot row and column have been found */
+    /* ---------------------------------------------------------------------- */
+
+    /* ---------------------------------------------------------------------- */
+    /* remove pivot column from candidate pivot column set */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (jj >= 0 && jj < Work->nCandidates) ;
+    ASSERT (Work->pivcol == Work->Candidates [jj]) ;
+    remove_candidate (jj, Work, Symbolic) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check for frontal matrix growth */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG1 (("Check frontal growth:\n")) ;
+    DEBUG1 (("fnrows_new "ID" + 1 = "ID",  fnr_curr "ID"\n",
+           Work->fnrows_new, Work->fnrows_new + 1, fnr_curr)) ;
+    DEBUG1 (("fncols_new "ID" + 1 = "ID",  fnc_curr "ID"\n",
+           Work->fncols_new, Work->fncols_new + 1, fnc_curr)) ;
+
+    Work->do_grow = (Work->fnrows_new + 1 > fnr_curr
+                 || Work->fncols_new + 1 > fnc_curr) ;
+    if (Work->do_grow)
+    {
+       DEBUG0 (("\nNeed to grow frontal matrix, force do_update true\n")) ;
+       /* If the front must grow, then apply the pending updates and remove
+        * the current pivot rows/columns from the front prior to growing the
+        * front.  This frees up as much space as possible for the new front. */
+       if (!Work->do_update && fnpiv > 0)
+       {
+           /* This update would not have to be done if the current front
+            * was big enough. */
+           Work->nforced++ ;
+           Work->do_update = TRUE ;
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* current pivot column */
+    /* ---------------------------------------------------------------------- */
+
+    /*
+       c1) If pivot column index is in the current front:
+
+           The pivot column pattern is in Frows [0 .. fnrows-1] and
+           the extension is in Frows [fnrows ... fnrows+ccdeg-1].
+
+           Frpos [Frows [0 .. fnrows+ccdeg-1]] is
+           equal to 0 .. fnrows+ccdeg-1.  Wm is not needed.
+
+           The values are in Wy [0 .. fnrows+ccdeg-1].
+
+       c2) Otherwise, if the pivot column index is not in the current front:
+
+           c2a) If the front is being extended, old row indices in the the
+               pivot column pattern are in Frows [0 .. fnrows-1].
+
+               All entries are in Wm [0 ... ccdeg-1], with values in
+               Wx [0 .. ccdeg-1].  These may include entries already in
+               Frows [0 .. fnrows-1].
+
+               Frpos [Frows [0 .. fnrows-1]] is equal to 0 .. fnrows-1.
+               Frpos [Wm [0 .. ccdeg-1]] for new entries is < 0.
+
+           c2b) If the front is not being extended, then the entire pivot
+               column pattern is in Wm [0 .. ccdeg-1].  It includes
+               the pivot row index.  It is does not contain the pattern
+               Frows [0..fnrows-1].  The intersection of these two
+               sets may or may not be empty.  The values are in Wx [0..ccdeg-1]
+
+       In both cases c1 and c2, Frpos [Frows [0 .. fnrows-1]] is equal
+       to 0 .. fnrows-1, which is the pattern of the current front.
+       Any entry of Frpos that is not specified above is < 0.
+    */
+
+
+#ifndef NDEBUG
+    DEBUG2 (("\n\nSEARCH DONE: Pivot col "ID" in: ("ID") pivot row "ID" in: ("ID
+       ") extend: "ID"\n\n", Work->pivcol, Work->pivcol_in_front,
+       Work->pivrow, Work->pivrow_in_front, Work->do_extend)) ;
+    UMF_dump_rowcol (1, Numeric, Work, Work->pivcol, !Symbolic->fixQ) ;
+    DEBUG2 (("Pivot col "ID": fnrows "ID" ccdeg "ID"\n", Work->pivcol, fnrows,
+       Work->ccdeg)) ;
+    if (Work->pivcol_in_front) /* case c1 */
+    {
+       Int found = FALSE ;
+       DEBUG3 (("Pivcol in front\n")) ;
+       for (i = 0 ; i < fnrows ; i++)
+       {
+           row = Frows [i] ;
+           DEBUG3 ((ID":   row:: "ID" in front ", i, row)) ;
+           ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ;
+           ASSERT (Frpos [row] == i) ;
+           EDEBUG3 (Wy [i]) ;
+           if (row == Work->pivrow)
+           {
+               DEBUG3 ((" <- pivrow")) ;
+               found = TRUE ;
+           }
+           DEBUG3 (("\n")) ;
+       }
+       ASSERT (found == Work->pivrow_in_front) ;
+       found = FALSE ;
+       for (i = fnrows ; i < fnrows + Work->ccdeg ; i++)
+       {
+           row = Frows [i] ;
+           DEBUG3 ((ID":   row:: "ID" (new)", i, row)) ;
+           ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ;
+           ASSERT (Frpos [row] == i) ;
+           EDEBUG3 (Wy [i]) ;
+           if (row == Work->pivrow)
+           {
+               DEBUG3 ((" <- pivrow")) ;
+               found = TRUE ;
+           }
+           DEBUG3 (("\n")) ;
+       }
+       ASSERT (found == !Work->pivrow_in_front) ;
+    }
+    else
+    {
+       if (Work->do_extend)
+       {
+           Int found = FALSE ;
+           DEBUG3 (("Pivcol not in front (extend)\n")) ;
+           for (i = 0 ; i < fnrows ; i++)
+           {
+               row = Frows [i] ;
+               DEBUG3 ((ID":   row:: "ID" in front ", i, row)) ;
+               ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ;
+               ASSERT (Frpos [row] == i) ;
+               if (row == Work->pivrow)
+               {
+                   DEBUG3 ((" <- pivrow")) ;
+                   found = TRUE ;
+               }
+               DEBUG3 (("\n")) ;
+           }
+           ASSERT (found == Work->pivrow_in_front) ;
+           found = FALSE ;
+           DEBUG3 (("----\n")) ;
+           for (i = 0 ; i < Work->ccdeg ; i++)
+           {
+               row = Wm [i] ;
+               ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ;
+               DEBUG3 ((ID":   row:: "ID" ", i, row)) ;
+               EDEBUG3 (Wx [i]) ;
+               if (Frpos [row] < 0)
+               {
+                   DEBUG3 ((" (new) ")) ;
+               }
+               if (row == Work->pivrow)
+               {
+                   DEBUG3 ((" <- pivrow")) ;
+                   found = TRUE ;
+                   /* ... */
+                   if (Work->pivrow_in_front) ASSERT (Frpos [row] >= 0) ;
+                   else ASSERT (Frpos [row] < 0) ;
+               }
+               DEBUG3 (("\n")) ;
+           }
+           ASSERT (found) ;
+       }
+       else
+       {
+           Int found = FALSE ;
+           DEBUG3 (("Pivcol not in front (no extend)\n")) ;
+           for (i = 0 ; i < Work->ccdeg ; i++)
+           {
+               row = Wm [i] ;
+               ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ;
+               DEBUG3 ((ID":   row:: "ID" ", i, row)) ;
+               EDEBUG3 (Wx [i]) ;
+               DEBUG3 ((" (new) ")) ;
+               if (row == Work->pivrow)
+               {
+                   DEBUG3 ((" <- pivrow")) ;
+                   found = TRUE ;
+               }
+               DEBUG3 (("\n")) ;
+           }
+           ASSERT (found) ;
+       }
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* current pivot row */
+    /* ---------------------------------------------------------------------- */
+
+    /*
+       r1) If the pivot row index is in the current front:
+
+           The pivot row pattern is in Fcols [0..fncols-1] and the extenson is
+           in Wrow [fncols .. rrdeg-1].  If the pivot column is in the current
+           front, then Fcols and Wrow are equivalenced.
+
+       r2)  If the pivot row index is not in the current front:
+
+           r2a) If the front is being extended, the pivot row pattern is in
+               Fcols [0 .. fncols-1].  New entries are in Wrow [0 .. rrdeg-1],
+               but these may include entries already in Fcols [0 .. fncols-1].
+
+           r2b) Otherwise, the pivot row pattern is Wrow [0 .. rrdeg-1].
+
+       Fcpos [Fcols [0..fncols-1]] is (0..fncols-1) * fnr_curr.
+       All other entries in Fcpos are < 0.
+
+       These conditions are asserted below.
+
+       ------------------------------------------------------------------------
+       Other items in Work structure that are relevant:
+
+       pivcol: the pivot column index
+       pivrow: the pivot column index
+
+       rrdeg:
+       ccdeg:
+
+       fnrows: the number of rows in the currnt contribution block
+       fncols: the number of columns in the current contribution block
+
+       fnrows_new: the number of rows in the new contribution block
+       fncols_new: the number of rows in the new contribution block
+
+       ------------------------------------------------------------------------
+    */
+
+
+#ifndef NDEBUG
+    UMF_dump_rowcol (0, Numeric, Work, Work->pivrow, TRUE) ;
+    DEBUG2 (("Pivot row "ID":\n", Work->pivrow)) ;
+    if (Work->pivrow_in_front)
+    {
+       Int found = FALSE ;
+       for (i = 0 ; i < fncols ; i++)
+       {
+           col = Fcols [i] ;
+           DEBUG3 (("   col:: "ID" in front\n", col)) ;
+           ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ;
+           ASSERT (Fcpos [col] == i * fnr_curr) ;
+           if (col == Work->pivcol) found = TRUE ;
+       }
+       ASSERT (found == Work->pivcol_in_front) ;
+       found = FALSE ;
+       ASSERT (IMPLIES (Work->pivcol_in_front, Fcols == Work->Wrow)) ;
+       for (i = fncols ; i < Work->rrdeg ; i++)
+       {
+           col = Work->Wrow [i] ;
+           ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ;
+           ASSERT (Fcpos [col] < 0) ;
+           if (col == Work->pivcol) found = TRUE ;
+           else DEBUG3 (("   col:: "ID" (new)\n", col)) ;
+       }
+       ASSERT (found == !Work->pivcol_in_front) ;
+    }
+    else
+    {
+       if (Work->do_extend)
+       {
+           Int found = FALSE ;
+           for (i = 0 ; i < fncols ; i++)
+           {
+               col = Fcols [i] ;
+               DEBUG3 (("   col:: "ID" in front\n", col)) ;
+               ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ;
+               ASSERT (Fcpos [col] == i * fnr_curr) ;
+               if (col == Work->pivcol) found = TRUE ;
+           }
+           ASSERT (found == Work->pivcol_in_front) ;
+           found = FALSE ;
+           for (i = 0 ; i < Work->rrdeg ; i++)
+           {
+               col = Work->Wrow [i] ;
+               ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ;
+               if (Fcpos [col] >= 0) continue ;
+               if (col == Work->pivcol) found = TRUE ;
+               else DEBUG3 (("   col:: "ID" (new, extend)\n", col)) ;
+           }
+           ASSERT (found == !Work->pivcol_in_front) ;
+       }
+       else
+       {
+           Int found = FALSE ;
+           for (i = 0 ; i < Work->rrdeg ; i++)
+           {
+               col = Work->Wrow [i] ;
+               ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ;
+               if (col == Work->pivcol) found = TRUE ;
+               else DEBUG3 (("   col:: "ID" (all new)\n", col)) ;
+           }
+           ASSERT (found) ;
+       }
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* determine whether to do scan2-row and scan2-col */
+    /* ---------------------------------------------------------------------- */
+
+    if (Work->do_extend)
+    {
+       Work->do_scan2row = (fncols > 0) ;
+       Work->do_scan2col = (fnrows > 0) ;
+    }
+    else
+    {
+       Work->do_scan2row = (fncols > 0) && Work->pivrow_in_front ;
+       Work->do_scan2col = (fnrows > 0) && Work->pivcol_in_front ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG2 (("LOCAL SEARCH DONE: pivot column "ID" pivot row: "ID"\n",
+       Work->pivcol, Work->pivrow)) ;
+    DEBUG2 (("do_extend: "ID"\n", Work->do_extend)) ;
+    DEBUG2 (("do_update: "ID"\n", Work->do_update)) ;
+    DEBUG2 (("do_grow:   "ID"\n", Work->do_grow)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* keep track of the diagonal */
+    /* ---------------------------------------------------------------------- */
+
+    if (Symbolic->prefer_diagonal
+       && Work->pivcol < Work->n_col - Symbolic->nempty_col)
+    {
+       Diagonal_map = Work->Diagonal_map ;
+       Diagonal_imap = Work->Diagonal_imap ;
+       ASSERT (Diagonal_map != (Int *) NULL) ;
+       ASSERT (Diagonal_imap != (Int *) NULL) ;
+
+       row2 = Diagonal_map  [Work->pivcol] ;
+       col2 = Diagonal_imap [Work->pivrow] ;
+
+       if (row2 < 0)
+       {
+           /* this was an off-diagonal pivot row */
+           Work->noff_diagonal++ ;
+           row2 = UNFLIP (row2) ;
+       }
+
+       ASSERT (Diagonal_imap [row2] == Work->pivcol) ;
+       ASSERT (UNFLIP (Diagonal_map [col2]) == Work->pivrow) ;
+
+       if (row2 != Work->pivrow)
+       {
+           /* swap the diagonal map to attempt to maintain symmetry later on.
+            * Also mark the map for col2 (via FLIP) to denote that the entry
+            * now on the diagonal is not the original entry on the diagonal. */
+
+           DEBUG0 (("Unsymmetric pivot\n")) ;
+           Diagonal_map  [Work->pivcol] = FLIP (Work->pivrow) ;
+           Diagonal_imap [Work->pivrow] = Work->pivcol ;
+
+           Diagonal_map  [col2] = FLIP (row2) ;
+           Diagonal_imap [row2] = col2 ;
+
+       }
+       ASSERT (n_row == n_col) ;
+#ifndef NDEBUG
+       UMF_dump_diagonal_map (Diagonal_map, Diagonal_imap, Symbolic->n1,
+           Symbolic->n_col, Symbolic->nempty_col) ;
+#endif
+    }
+
+    return (UMFPACK_OK) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_local_search.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_local_search.h
new file mode 100644 (file)
index 0000000..51ca38b
--- /dev/null
@@ -0,0 +1,13 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_local_search
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    SymbolicType *Symbolic
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_lsolve.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_lsolve.c
new file mode 100644 (file)
index 0000000..03a84a3
--- /dev/null
@@ -0,0 +1,151 @@
+/* ========================================================================== */
+/* === UMF_lsolve =========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*  solves Lx = b, where L is the lower triangular factor of a matrix */
+/*  B is overwritten with the solution X. */
+/*  Returns the floating point operation count */
+
+#include "umf_internal.h"
+
+GLOBAL double UMF_lsolve
+(
+    NumericType *Numeric,
+    Entry X [ ],               /* b on input, solution x on output */
+    Int Pattern [ ]            /* a work array of size n */
+)
+{
+    Int k, deg, *ip, j, row, *Lpos, *Lilen, *Lip, llen, lp, newLchain,
+       pos, npiv, n1, *Li ;
+    Entry *xp, xk, *Lval ;
+
+    /* ---------------------------------------------------------------------- */
+
+    if (Numeric->n_row != Numeric->n_col) return (0.) ;
+    npiv = Numeric->npiv ;
+    Lpos = Numeric->Lpos ;
+    Lilen = Numeric->Lilen ;
+    Lip = Numeric->Lip ;
+    n1 = Numeric->n1 ;
+
+#ifndef NDEBUG
+    DEBUG4 (("Lsolve start:\n")) ;
+    for (j = 0 ; j < Numeric->n_row ; j++)
+    {
+       DEBUG4 (("Lsolve start "ID": ", j)) ;
+       EDEBUG4 (X [j]) ;
+       DEBUG4 (("\n")) ;
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* singletons */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = 0 ; k < n1 ; k++)
+    {
+       DEBUG4 (("Singleton k "ID"\n", k)) ;
+       xk = X [k] ;
+       deg = Lilen [k] ;
+       if (deg > 0 && IS_NONZERO (xk))
+       {
+           lp = Lip [k] ;
+           Li = (Int *) (Numeric->Memory + lp) ;
+           lp += UNITS (Int, deg) ;
+           Lval = (Entry *) (Numeric->Memory + lp) ;
+           for (j = 0 ; j < deg ; j++)
+           {
+               DEBUG4 (("  row "ID"  k "ID" value", Li [j], k)) ;
+               EDEBUG4 (Lval [j]) ;
+               DEBUG4 (("\n")) ;
+               /* X [Li [j]] -= xk * Lval [j] ; */
+               MULT_SUB (X [Li [j]], xk, Lval [j]) ;
+           }
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* rest of L */
+    /* ---------------------------------------------------------------------- */
+
+    deg = 0 ;
+
+    for (k = n1 ; k < npiv ; k++)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* make column of L in Pattern [0..deg-1] */
+       /* ------------------------------------------------------------------ */
+
+       lp = Lip [k] ;
+       newLchain = (lp < 0) ;
+       if (newLchain)
+       {
+           lp = -lp ;
+           deg = 0 ;
+           DEBUG4 (("start of chain for column of L\n")) ;
+       }
+
+       /* remove pivot row */
+       pos = Lpos [k] ;
+       if (pos != EMPTY)
+       {
+           DEBUG4 (("  k "ID" removing row "ID" at position "ID"\n",
+           k, Pattern [pos], pos)) ;
+           ASSERT (!newLchain) ;
+           ASSERT (deg > 0) ;
+           ASSERT (pos >= 0 && pos < deg) ;
+           ASSERT (Pattern [pos] == k) ;
+           Pattern [pos] = Pattern [--deg] ;
+       }
+
+       /* concatenate the pattern */
+       ip = (Int *) (Numeric->Memory + lp) ;
+       llen = Lilen [k] ;
+       for (j = 0 ; j < llen ; j++)
+       {
+           row = *ip++ ;
+           DEBUG4 (("  row "ID"  k "ID"\n", row, k)) ;
+           ASSERT (row > k) ;
+           Pattern [deg++] = row ;
+       }
+
+       /* ------------------------------------------------------------------ */
+       /* use column k of L */
+       /* ------------------------------------------------------------------ */
+
+       xk = X [k] ;
+       if (IS_NONZERO (xk))
+       {
+           xp = (Entry *) (Numeric->Memory + lp + UNITS (Int, llen)) ;
+           for (j = 0 ; j < deg ; j++)
+           {
+               DEBUG4 (("  row "ID"  k "ID" value", Pattern [j], k)) ;
+               EDEBUG4 (*xp) ;
+               DEBUG4 (("\n")) ;
+               /* X [Pattern [j]] -= xk * (*xp) ; */
+               MULT_SUB (X [Pattern [j]], xk, *xp) ;
+               xp++ ;
+           }
+       }
+    }
+
+#ifndef NDEBUG
+    for (j = 0 ; j < Numeric->n_row ; j++)
+    {
+       DEBUG4 (("Lsolve done "ID": ", j)) ;
+       EDEBUG4 (X [j]) ;
+       DEBUG4 (("\n")) ;
+    }
+    DEBUG4 (("Lsolve done.\n")) ;
+#endif
+
+    return (MULTSUB_FLOPS * ((double) Numeric->lnz)) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_lsolve.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_lsolve.h
new file mode 100644 (file)
index 0000000..75d6467
--- /dev/null
@@ -0,0 +1,13 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL double UMF_lsolve
+(
+    NumericType *Numeric,
+    Entry X [ ],
+    Int Pattern [ ]
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_ltsolve.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_ltsolve.c
new file mode 100644 (file)
index 0000000..6011f0c
--- /dev/null
@@ -0,0 +1,225 @@
+/* ========================================================================== */
+/* === UMF_ltsolve ========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*  Solves L'x = b or L.'x=b, where L is the lower triangular factor of a */
+/*  matrix.  B is overwritten with the solution X. */
+/*  Returns the floating point operation count */
+
+#include "umf_internal.h"
+
+GLOBAL double
+#ifdef CONJUGATE_SOLVE
+UMF_lhsolve                    /* solve L'x=b  (complex conjugate transpose) */
+#else
+UMF_ltsolve                    /* solve L.'x=b (array transpose) */
+#endif
+(
+    NumericType *Numeric,
+    Entry X [ ],               /* b on input, solution x on output */
+    Int Pattern [ ]            /* a work array of size n */
+)
+{
+    Int k, deg, *ip, j, row, *Lpos, *Lilen, kstart, kend, *Lip, llen,
+       lp, pos, npiv, n1, *Li ;
+    Entry *xp, xk, *Lval ;
+
+    /* ---------------------------------------------------------------------- */
+
+    if (Numeric->n_row != Numeric->n_col) return (0.) ;
+    npiv = Numeric->npiv ;
+    Lpos = Numeric->Lpos ;
+    Lilen = Numeric->Lilen ;
+    Lip = Numeric->Lip ;
+    kstart = npiv ;
+    n1 = Numeric->n1 ;
+
+#ifndef NDEBUG
+    DEBUG4 (("Ltsolve start:\n")) ;
+    for (j = 0 ; j < Numeric->n_row ; j++)
+    {
+       DEBUG4 (("Ltsolve start "ID": ", j)) ;
+       EDEBUG4 (X [j]) ;
+       DEBUG4 (("\n")) ;
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* non-singletons */
+    /* ---------------------------------------------------------------------- */
+
+    for (kend = npiv-1 ; kend >= n1 ; kend = kstart-1)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* find the start of this Lchain */
+       /* ------------------------------------------------------------------ */
+
+       /* for (kstart = kend ; kstart >= 0 && Lip [kstart] > 0 ; kstart--) ; */
+       kstart = kend ;
+       while (kstart >= 0 && Lip [kstart] > 0)
+       {
+           kstart-- ;
+       }
+
+       /* the Lchain goes from kstart to kend */
+
+       /* ------------------------------------------------------------------ */
+       /* scan the whole chain to find the pattern of the last column of L */
+       /* ------------------------------------------------------------------ */
+
+       deg = 0 ;
+       DEBUG4 (("start of chain for column of L\n")) ;
+       for (k = kstart ; k <= kend ; k++)
+       {
+           ASSERT (k >= 0 && k < npiv) ;
+
+           /* -------------------------------------------------------------- */
+           /* make column k of L in Pattern [0..deg-1] */
+           /* -------------------------------------------------------------- */
+
+           /* remove pivot row */
+           pos = Lpos [k] ;
+           if (pos != EMPTY)
+           {
+               DEBUG4 (("  k "ID" removing row "ID" at position "ID"\n",
+               k, Pattern [pos], pos)) ;
+               ASSERT (k != kstart) ;
+               ASSERT (deg > 0) ;
+               ASSERT (pos >= 0 && pos < deg) ;
+               ASSERT (Pattern [pos] == k) ;
+               Pattern [pos] = Pattern [--deg] ;
+           }
+
+           /* concatenate the pattern */
+           lp = Lip [k] ;
+           if (k == kstart)
+           {
+               lp = -lp ;
+           }
+           ASSERT (lp > 0) ;
+           ip = (Int *) (Numeric->Memory + lp) ;
+           llen = Lilen [k] ;
+           for (j = 0 ; j < llen ; j++)
+           {
+               row = *ip++ ;
+               DEBUG4 (("  row "ID"  k "ID"\n", row, k)) ;
+               ASSERT (row > k) ;
+               Pattern [deg++] = row ;
+           }
+
+       }
+       /* Pattern [0..deg-1] is now the pattern of column kend */
+
+       /* ------------------------------------------------------------------ */
+       /* solve using this chain, in reverse order */
+       /* ------------------------------------------------------------------ */
+
+       DEBUG4 (("Unwinding Lchain\n")) ;
+       for (k = kend ; k >= kstart ; k--)
+       {
+
+           /* -------------------------------------------------------------- */
+           /* use column k of L */
+           /* -------------------------------------------------------------- */
+
+           ASSERT (k >= 0 && k < npiv) ;
+           lp = Lip [k] ;
+           if (k == kstart)
+           {
+               lp = -lp ;
+           }
+           ASSERT (lp > 0) ;
+           llen = Lilen [k] ;
+           xp = (Entry *) (Numeric->Memory + lp + UNITS (Int, llen)) ;
+           xk = X [k] ;
+           for (j = 0 ; j < deg ; j++)
+           {
+               DEBUG4 (("  row "ID"  k "ID" value", Pattern [j], k)) ;
+               EDEBUG4 (*xp) ;
+               DEBUG4 (("\n")) ;
+
+#ifdef CONJUGATE_SOLVE
+               /* xk -= X [Pattern [j]] * conjugate (*xp) ; */
+               MULT_SUB_CONJ (xk, X [Pattern [j]], *xp) ;
+#else
+               /* xk -= X [Pattern [j]] * (*xp) ; */
+               MULT_SUB (xk, X [Pattern [j]], *xp) ;
+#endif
+
+               xp++ ;
+           }
+           X [k] = xk ;
+
+           /* -------------------------------------------------------------- */
+           /* construct column k-1 of L */
+           /* -------------------------------------------------------------- */
+
+           /* un-concatenate the pattern */
+           deg -= llen ;
+
+           /* add pivot row */
+           pos = Lpos [k] ;
+           if (pos != EMPTY)
+           {
+               DEBUG4 (("  k "ID" adding row "ID" at position "ID"\n",
+               k, k, pos)) ;
+               ASSERT (k != kstart) ;
+               ASSERT (pos >= 0 && pos <= deg) ;
+               Pattern [deg++] = Pattern [pos] ;
+               Pattern [pos] = k ;
+           }
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* singletons */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = n1 - 1 ; k >= 0 ; k--)
+    {
+       DEBUG4 (("Singleton k "ID"\n", k)) ;
+       deg = Lilen [k] ;
+       if (deg > 0)
+       {
+           xk = X [k] ;
+           lp = Lip [k] ;
+           Li = (Int *) (Numeric->Memory + lp) ;
+           lp += UNITS (Int, deg) ;
+           Lval = (Entry *) (Numeric->Memory + lp) ;
+           for (j = 0 ; j < deg ; j++)
+           {
+               DEBUG4 (("  row "ID"  k "ID" value", Li [j], k)) ;
+               EDEBUG4 (Lval [j]) ;
+               DEBUG4 (("\n")) ;
+#ifdef CONJUGATE_SOLVE
+               /* xk -= X [Li [j]] * conjugate (Lval [j]) ; */
+               MULT_SUB_CONJ (xk, X [Li [j]], Lval [j]) ;
+#else
+               /* xk -= X [Li [j]] * Lval [j] ; */
+               MULT_SUB (xk, X [Li [j]], Lval [j]) ;
+#endif
+           }
+           X [k] = xk ;
+       }
+    }
+
+#ifndef NDEBUG
+    for (j = 0 ; j < Numeric->n_row ; j++)
+    {
+       DEBUG4 (("Ltsolve done "ID": ", j)) ;
+       EDEBUG4 (X [j]) ;
+       DEBUG4 (("\n")) ;
+    }
+    DEBUG4 (("Ltsolve done.\n")) ;
+#endif
+
+    return (MULTSUB_FLOPS * ((double) Numeric->lnz)) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_ltsolve.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_ltsolve.h
new file mode 100644 (file)
index 0000000..3b4ad1f
--- /dev/null
@@ -0,0 +1,20 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL double UMF_ltsolve
+(
+    NumericType *Numeric,
+    Entry X [ ],
+    Int Pattern [ ]
+) ;
+
+GLOBAL double UMF_lhsolve
+(
+    NumericType *Numeric,
+    Entry X [ ],
+    Int Pattern [ ]
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_malloc.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_malloc.c
new file mode 100644 (file)
index 0000000..9416435
--- /dev/null
@@ -0,0 +1,92 @@
+/* ========================================================================== */
+/* === UMF_malloc =========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Allocate a block of n objects, each of a given size.  This routine does not
+    handle the case when the size is 1 (allocating char's) because of potential
+    integer overflow.  UMFPACK never does that.
+    Also maintains the UMFPACK malloc count.
+*/
+
+#include "umf_internal.h"
+
+#if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG)
+
+/*
+    UMF_malloc_count is a count of the objects malloc'd by UMFPACK.  If you
+    suspect a memory leak in your program (caused by not properly destroying
+    the Symbolic and Numeric objects) then compile with -DUMF_MALLOC_COUNT and
+    check value of UMF_malloc_count.  By default, UMF_MALLOC_COUNT is not
+    defined, and thus UMFPACK has no global variables.
+*/
+
+GLOBAL Int UMF_malloc_count = 0 ;
+
+#endif
+
+#ifdef UMF_TCOV_TEST
+/* For exhaustive statement coverage testing only! */
+GLOBAL Int umf_fail, umf_fail_lo, umf_fail_hi ;
+GLOBAL Int umf_realloc_fail, umf_realloc_lo, umf_realloc_hi ;
+#endif
+
+GLOBAL void *UMF_malloc
+(
+    Int n_objects,
+    size_t size_of_object
+)
+{
+    size_t size ;
+    void *p ;
+
+#ifdef UMF_TCOV_TEST
+    /* For exhaustive statement coverage testing only! */
+    /* Pretend to fail, to test out-of-memory conditions. */
+    umf_fail-- ;
+    if (umf_fail <= umf_fail_hi && umf_fail >= umf_fail_lo)
+    {
+       DEBUG0 (("umf_malloc: Pretend to fail %d %d %d\n",
+           umf_fail, umf_fail_hi, umf_fail_lo)) ;
+       return ((void *) NULL) ;
+    }
+#endif
+
+    DEBUG0 (("UMF_malloc: ")) ;
+
+    /* make sure that we allocate something */
+    n_objects = MAX (1, n_objects) ;
+
+    size = (size_t) n_objects ;
+    ASSERT (size_of_object > 1) ;
+    if (size > Int_MAX / size_of_object)
+    {
+       /* object is too big for integer pointer arithmetic */
+       return ((void *) NULL) ;
+    }
+    size *= size_of_object ;
+
+    /* see umf_config.h for the memory allocator selection */
+    p = ALLOCATE (size) ;
+
+    DEBUG0 ((ID"\n", (Int) p)) ;
+
+#if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG)
+    if (p)
+    {
+       /* One more object has been malloc'ed.  Keep track of the count. */
+       /* (purely for sanity checks). */
+       UMF_malloc_count++ ;
+       DEBUG0 (("  successful, new malloc count: "ID"\n", UMF_malloc_count)) ;
+    }
+#endif
+
+    return (p) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_malloc.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_malloc.h
new file mode 100644 (file)
index 0000000..44529b5
--- /dev/null
@@ -0,0 +1,16 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+#if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG)
+GLOBAL extern Int UMF_malloc_count ;
+#endif
+
+GLOBAL void *UMF_malloc
+(
+    Int n_objects,
+    size_t size_of_object
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_element.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_element.c
new file mode 100644 (file)
index 0000000..6eefa35
--- /dev/null
@@ -0,0 +1,83 @@
+/* ========================================================================== */
+/* === UMF_mem_alloc_element ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* The UMF_mem_* routines manage the Numeric->Memory memory space. */
+
+/* Allocate a nrows-by-ncols element, and initialize it. */
+/* Returns the index into Numeric->Memory if successful, or 0 on failure. */
+
+#include "umf_internal.h"
+#include "umf_mem_alloc_tail_block.h"
+
+GLOBAL Int UMF_mem_alloc_element
+(
+    NumericType *Numeric,
+    Int nrows,
+    Int ncols,
+    Int **Rows,
+    Int **Cols,
+    Entry **C,
+    Int *size,
+    Element **epout
+)
+{
+
+    Element *ep ;
+    Unit *p ;
+    Int i ;
+
+    ASSERT (Numeric != (NumericType *) NULL) ;
+    ASSERT (Numeric->Memory != (Unit *) NULL) ;
+
+    *size = GET_ELEMENT_SIZE (nrows, ncols) ;
+    if (INT_OVERFLOW (DGET_ELEMENT_SIZE (nrows, ncols) + 1))
+    {
+       /* :: allocate element, int overflow :: */
+       return (0) ;    /* problem is too large */
+    }
+
+    i = UMF_mem_alloc_tail_block (Numeric, *size) ;
+    (*size)++ ;
+    if (!i)
+    {
+       DEBUG0 (("alloc element failed - out of memory\n")) ;
+       return (0) ;    /* out of memory */
+    }
+    p = Numeric->Memory + i ;
+
+    ep = (Element *) p ;
+
+    DEBUG2 (("alloc_element done ("ID" x "ID"): p: "ID" i "ID"\n",
+       nrows, ncols, (Int) (p-Numeric->Memory), i)) ;
+
+    /* Element data structure, in order: */
+    p += UNITS (Element, 1) ;          /* (1) Element header */
+    *Cols = (Int *) p ;                        /* (2) col [0..ncols-1] indices */
+    *Rows = *Cols + ncols ;            /* (3) row [0..nrows-1] indices */
+    p += UNITS (Int, ncols + nrows) ;
+    *C = (Entry *) p ;                 /* (4) C [0..nrows-1, 0..ncols-1] */
+
+    ep->nrows = nrows ;                /* initialize the header information */
+    ep->ncols = ncols ;
+    ep->nrowsleft = nrows ;
+    ep->ncolsleft = ncols ;
+    ep->cdeg = 0 ;
+    ep->rdeg = 0 ;
+    ep->next = EMPTY ;
+
+    DEBUG2 (("new block size: "ID" ", GET_BLOCK_SIZE (Numeric->Memory + i))) ;
+    DEBUG2 (("Element size needed "ID"\n", GET_ELEMENT_SIZE (nrows, ncols))) ;
+
+    *epout = ep ;
+
+    /* return the offset into Numeric->Memory */
+    return (i) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_element.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_element.h
new file mode 100644 (file)
index 0000000..b3886cf
--- /dev/null
@@ -0,0 +1,18 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_mem_alloc_element
+(
+    NumericType *Numeric,
+    Int nrows,
+    Int ncols,
+    Int **Rows,
+    Int **Cols,
+    Entry **C,
+    Int *size,
+    Element **epout
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_head_block.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_head_block.c
new file mode 100644 (file)
index 0000000..9f94c2c
--- /dev/null
@@ -0,0 +1,55 @@
+/* ========================================================================== */
+/* === UMF_mem_alloc_head_block ============================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* The UMF_mem_* routines manage the Numeric->Memory memory space. */
+
+/* allocate nunits from head of Numeric->Memory.  No header allocated. */
+/* Returns the index into Numeric->Memory if successful, or 0 on failure. */
+
+#include "umf_internal.h"
+
+GLOBAL Int UMF_mem_alloc_head_block
+(
+    NumericType *Numeric,
+    Int nunits
+)
+{
+    Int p, usage ;
+    DEBUG2 (("GET  BLOCK: from head, size "ID" ", nunits)) ;
+
+    ASSERT (Numeric != (NumericType *) NULL) ;
+    ASSERT (Numeric->Memory != (Unit *) NULL) ;
+
+#ifndef NDEBUG
+    if (UMF_allocfail)
+    {
+       /* pretend to fail, to test garbage_collection */
+       DEBUGm2 (("UMF_mem_alloc_head_block: pretend to fail\n")) ;
+       UMF_allocfail = FALSE ; /* don't fail the next time */
+       return (0) ;
+    }
+#endif
+
+    if (nunits > (Numeric->itail - Numeric->ihead))
+    {
+       DEBUG2 ((" failed\n")) ;
+       return (0) ;
+    }
+
+    /* return p as an offset from Numeric->Memory */
+    p = Numeric->ihead ;
+    Numeric->ihead += nunits ;
+
+    DEBUG2 (("p: "ID"\n", p)) ;
+    usage = Numeric->ihead + Numeric->tail_usage ;
+    Numeric->max_usage = MAX (Numeric->max_usage, usage) ;
+    return (p) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_head_block.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_head_block.h
new file mode 100644 (file)
index 0000000..7217e51
--- /dev/null
@@ -0,0 +1,12 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_mem_alloc_head_block
+(
+    NumericType *Numeric,
+    Int nunits
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_tail_block.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_tail_block.c
new file mode 100644 (file)
index 0000000..a6ca5cf
--- /dev/null
@@ -0,0 +1,134 @@
+/* ========================================================================== */
+/* === UMF_mem_alloc_tail_block ============================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* The UMF_mem_* routines manage the Numeric->Memory memory space. */
+
+#include "umf_internal.h"
+
+/* allocate nunits from tail of Numeric->Memory */
+/* (requires nunits+1, for header). */
+/* Returns the index into Numeric->Memory if successful, or 0 on failure. */
+
+GLOBAL Int UMF_mem_alloc_tail_block
+(
+    NumericType *Numeric,
+    Int nunits
+)
+{
+    Int bigsize, usage ;
+    Unit *p, *pnext, *pbig ;
+
+    ASSERT (Numeric != (NumericType *) NULL) ;
+    ASSERT (Numeric->Memory != (Unit *) NULL) ;
+
+#ifndef NDEBUG
+    if (UMF_allocfail)
+    {
+       /* pretend to fail, to test garbage_collection */
+       DEBUGm2 (("UMF_mem_alloc_tail_block: pretend to fail\n")) ;
+       UMF_allocfail = FALSE ; /* don't fail the next time */
+       return (0) ;
+    }
+    DEBUG2 (("UMF_mem_alloc_tail_block, size: "ID" + 1 = "ID":  ",
+       nunits, nunits+1)) ;
+#endif
+
+    bigsize = 0 ;
+    pbig = (Unit *) NULL ;
+
+    ASSERT (nunits > 0) ;      /* size must be positive */
+    if (Numeric->ibig != EMPTY)
+    {
+       ASSERT (Numeric->ibig > Numeric->itail) ;
+       ASSERT (Numeric->ibig < Numeric->size) ;
+       pbig = Numeric->Memory + Numeric->ibig ;
+       bigsize = -pbig->header.size ;
+       ASSERT (bigsize > 0) ;  /* Numeric->ibig is free */
+       ASSERT (pbig->header.prevsize >= 0) ;   /* prev. is not free */
+    }
+
+    if (pbig && bigsize >= nunits)
+    {
+
+       /* use the biggest block, somewhere in middle of memory */
+       p = pbig ;
+       pnext = p + 1 + bigsize ;
+       /* next is in range */
+       ASSERT (pnext < Numeric->Memory + Numeric->size) ;
+       /* prevsize of next = this size */
+       ASSERT (pnext->header.prevsize == bigsize) ;
+       /* next is not free */
+       ASSERT (pnext->header.size > 0) ;
+       bigsize -= nunits + 1 ;
+
+       if (bigsize < 4)
+       {
+           /* internal fragmentation would be too small */
+           /* allocate the entire free block */
+           p->header.size = -p->header.size ;
+           DEBUG2 (("GET  BLOCK: p: "ID" size: "ID", all of big: "ID" size: "
+               ID"\n", (Int) (p-Numeric->Memory), nunits, Numeric->ibig,
+               p->header.size)) ;
+           /* no more biggest block */
+           Numeric->ibig = EMPTY ;
+
+       }
+       else
+       {
+
+           /* allocate just the first nunits Units of the free block */
+           p->header.size = nunits ;
+           /* make a new free block */
+           Numeric->ibig += nunits + 1 ;
+           pbig = Numeric->Memory + Numeric->ibig ;
+           pbig->header.size = -bigsize ;
+           pbig->header.prevsize = nunits ;
+           pnext->header.prevsize = bigsize ;
+           DEBUG2 (("GET  BLOCK: p: "ID" size: "ID", some of big: "ID" left: "
+               ID"\n", (Int) (p-Numeric->Memory), nunits, Numeric->ibig,
+               bigsize)) ;
+       }
+
+    }
+    else
+    {
+
+       /* allocate from the top of tail */
+       pnext = Numeric->Memory + Numeric->itail ;
+       DEBUG2 (("GET  BLOCK: from tail ")) ;
+       if ((nunits + 1) > (Numeric->itail - Numeric->ihead))
+       {
+           DEBUG2 (("\n")) ;
+           return (0) ;
+       }
+       Numeric->itail -= (nunits + 1) ;
+       p = Numeric->Memory + Numeric->itail ;
+       p->header.size = nunits ;
+       p->header.prevsize = 0 ;
+       pnext->header.prevsize = nunits ;
+       DEBUG2 (("p: "ID" size: "ID", new tail "ID"\n",
+           (Int) (p-Numeric->Memory), nunits, Numeric->itail)) ;
+    }
+
+    Numeric->tail_usage += p->header.size + 1 ;
+    usage = Numeric->ihead + Numeric->tail_usage ;
+    Numeric->max_usage = MAX (Numeric->max_usage, usage) ;
+
+#ifndef NDEBUG
+    UMF_debug -= 10 ;
+    UMF_dump_memory (Numeric) ;
+    UMF_debug += 10 ;
+#endif
+
+    /* p points to the header.  Add one to point to the usable block itself. */
+    /* return the offset into Numeric->Memory */
+    return ((p - Numeric->Memory) + 1) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_tail_block.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_tail_block.h
new file mode 100644 (file)
index 0000000..b0502e0
--- /dev/null
@@ -0,0 +1,12 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_mem_alloc_tail_block
+(
+    NumericType *Numeric,
+    Int nunits
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_free_tail_block.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_free_tail_block.c
new file mode 100644 (file)
index 0000000..842d4bc
--- /dev/null
@@ -0,0 +1,143 @@
+/* ========================================================================== */
+/* === UMF_mem_free_tail_block ============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* The UMF_mem_* routines manage the Numeric->Memory memory space. */
+
+/* free a block from the tail of Numeric->memory */
+
+#include "umf_internal.h"
+
+GLOBAL void UMF_mem_free_tail_block
+(
+    NumericType *Numeric,
+    Int i
+)
+{
+    Unit *pprev, *pnext, *p, *pbig ;
+    Int sprev ;
+
+    ASSERT (Numeric != (NumericType *) NULL) ;
+    ASSERT (Numeric->Memory != (Unit *) NULL) ;
+    if (i == EMPTY || i == 0) return ; /* already deallocated */
+
+    /* ---------------------------------------------------------------------- */
+    /* get the block */
+    /* ---------------------------------------------------------------------- */
+
+    p = Numeric->Memory + i ;
+
+    p-- ;      /* get the corresponding header */
+    DEBUG2 (("free block: p: "ID, (Int) (p-Numeric->Memory))) ;
+    ASSERT (p >= Numeric->Memory + Numeric->itail) ;
+    ASSERT (p < Numeric->Memory + Numeric->size) ;
+    ASSERT (p->header.size > 0) ;              /* block not already free */
+    ASSERT (p->header.prevsize >= 0) ;
+
+    Numeric->tail_usage -= p->header.size + 1 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* merge with next free block, if any */
+    /* ---------------------------------------------------------------------- */
+
+    pnext = p + 1 + p->header.size ;
+    DEBUG2 (("size: "ID" next: "ID" ", p->header.size,
+       (Int) (pnext-Numeric->Memory))) ;
+    ASSERT (pnext < Numeric->Memory + Numeric->size) ;
+    ASSERT (pnext->header.prevsize == p->header.size) ;
+    ASSERT (pnext->header.size != 0) ;
+
+    if (pnext->header.size < 0)
+    {
+       /* next block is also free - merge with current block */
+       p->header.size += (-(pnext->header.size)) + 1 ;
+       DEBUG2 ((" NEXT FREE ")) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* merge with previous free block, if any */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    if (p == Numeric->Memory + Numeric->itail)
+    {
+       DEBUG2 ((" at top of tail ")) ;
+       ASSERT (p->header.prevsize == 0) ;
+    }
+#endif
+
+    if (p > Numeric->Memory + Numeric->itail)
+    {
+       ASSERT (p->header.prevsize > 0) ;
+       pprev = p - 1 - p->header.prevsize ;
+       DEBUG2 ((" prev: "ID" ", (Int) (pprev-Numeric->Memory))) ;
+       ASSERT (pprev >= Numeric->Memory + Numeric->itail) ;
+       sprev = pprev->header.size ;
+       if (sprev < 0)
+       {
+           /* previous block is also free - merge it with current block */
+           ASSERT (p->header.prevsize == -sprev) ;
+           pprev->header.size = p->header.size + (-sprev) + 1 ;
+           p = pprev ;
+           DEBUG2 ((" PREV FREE ")) ;
+           /* note that p may now point to Numeric->itail */
+       }
+#ifndef NDEBUG
+       else
+       {
+           ASSERT (p->header.prevsize == sprev) ;
+       }
+#endif
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* free the block, p */
+    /* ---------------------------------------------------------------------- */
+
+    pnext = p + 1 + p->header.size ;
+    ASSERT (pnext < Numeric->Memory + Numeric->size) ;
+
+    if (p == Numeric->Memory + Numeric->itail)
+    {
+       /* top block in list is freed */
+       Numeric->itail = pnext - Numeric->Memory ;
+       pnext->header.prevsize = 0 ;
+       DEBUG2 ((" NEW TAIL : "ID" ", Numeric->itail)) ;
+       ASSERT (pnext->header.size > 0) ;
+       if (Numeric->ibig != EMPTY && Numeric->ibig <= Numeric->itail)
+       {
+           /* the big free block is now above the tail */
+           Numeric->ibig = EMPTY ;
+       }
+    }
+    else
+    {
+       /* keep track of the biggest free block seen */
+       if (Numeric->ibig == EMPTY)
+       {
+           Numeric->ibig = p - Numeric->Memory ;
+       }
+       else
+       {
+           pbig = Numeric->Memory + Numeric->ibig ;
+           if (-(pbig->header.size) < p->header.size)
+           {
+               Numeric->ibig = p - Numeric->Memory ;
+           }
+       }
+       /* flag the block as free, somewhere in the middle of the tail */
+       pnext->header.prevsize = p->header.size ;
+       p->header.size = -(p->header.size) ;
+    }
+
+    DEBUG2 (("new p: "ID" freesize: "ID"\n", (Int) (p-Numeric->Memory),
+       -(p->header.size))) ;
+
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_free_tail_block.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_free_tail_block.h
new file mode 100644 (file)
index 0000000..87b232b
--- /dev/null
@@ -0,0 +1,12 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_mem_free_tail_block
+(
+    NumericType *Numeric,
+    Int i
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_init_memoryspace.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_init_memoryspace.c
new file mode 100644 (file)
index 0000000..5a2310d
--- /dev/null
@@ -0,0 +1,65 @@
+/* ========================================================================== */
+/* === UMF_mem_init_memoryspace ============================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* The UMF_mem_* routines manage the Numeric->Memory memory space. */
+
+#include "umf_internal.h"
+
+/* initialize the LU and element workspace (Numeric->Memory) */
+
+GLOBAL void UMF_mem_init_memoryspace
+(
+    NumericType *Numeric
+)
+{
+    Unit *p ;
+
+    ASSERT (Numeric != (NumericType *) NULL) ;
+    ASSERT (Numeric->Memory != (Unit *) NULL) ;
+    ASSERT (Numeric->size >= 3) ;
+    DEBUG0 (("Init memory space, size "ID"\n", Numeric->size)) ;
+
+    Numeric->ngarbage = 0 ;
+    Numeric->nrealloc = 0 ;
+    Numeric->ncostly = 0 ;
+    Numeric->ibig = EMPTY ;
+    Numeric->ihead = 0 ;
+    Numeric->itail = Numeric->size ;
+
+#ifndef NDEBUG
+    UMF_allocfail = FALSE ;
+#endif
+
+    /* allocate the 2-unit tail marker block and initialize it */
+    Numeric->itail -= 2 ;
+    p = Numeric->Memory + Numeric->itail ;
+    DEBUG2 (("p "ID" tail "ID"\n", (Int) (p-Numeric->Memory), Numeric->itail)) ;
+    Numeric->tail_usage = 2 ;
+    p->header.prevsize = 0 ;
+    p->header.size = 1 ;
+
+    /* allocate a 1-unit head marker block at the head of memory */
+    /* this is done so that an offset of zero is treated as a NULL pointer */
+    Numeric->ihead++ ;
+
+    /* initial usage in Numeric->Memory */
+    Numeric->max_usage = 3 ;
+    Numeric->init_usage = Numeric->max_usage ;
+
+    /* Note that UMFPACK_*symbolic ensures that Numeric->Memory is of size */
+    /* at least 3, so this initialization will always succeed. */
+
+#ifndef NDEBUG
+    DEBUG2 (("init_memoryspace, all free (except one unit at head\n")) ;
+    UMF_dump_memory (Numeric) ;
+#endif
+
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_init_memoryspace.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_init_memoryspace.h
new file mode 100644 (file)
index 0000000..8626eeb
--- /dev/null
@@ -0,0 +1,11 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_mem_init_memoryspace
+(
+    NumericType *Numeric
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_realloc.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_realloc.c
new file mode 100644 (file)
index 0000000..339705b
--- /dev/null
@@ -0,0 +1,76 @@
+/* ========================================================================== */
+/* === UMF_realloc ========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Realloc a block previously allocated by UMF_malloc.
+    Return NULL on failure (in which case the block is still allocated, and will
+    be kept at is present size).  This routine is only used for Numeric->Memory.
+*/
+
+#include "umf_internal.h"
+
+#if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG)
+#include "umf_malloc.h"
+#endif
+
+GLOBAL void *UMF_realloc
+(
+    void *p,
+    Int n_objects,
+    size_t size_of_object
+)
+{
+    size_t size ;
+    void *p2 ;
+
+#ifdef UMF_TCOV_TEST
+    /* For exhaustive statement coverage testing only! */
+    /* Pretend to fail, to test out-of-memory conditions. */
+    umf_realloc_fail-- ;
+    if (umf_realloc_fail <= umf_realloc_hi &&
+       umf_realloc_fail >= umf_realloc_lo)
+    {
+       return ((void *) NULL) ;
+    }
+#endif
+
+    /* make sure that we allocate something */
+    n_objects = MAX (1, n_objects) ;
+
+    size = (size_t) n_objects ;
+    ASSERT (size_of_object > 1) ;
+    if (size > Int_MAX / size_of_object)
+    {
+       /* :: int overflow in umf_realloc :: */
+       return ((void *) NULL) ;
+    }
+    size *= size_of_object ;
+
+    DEBUG0 (("UMF_realloc: "ID" n_objects "ID"  size_of_object "ID"\n",
+       (Int) p, n_objects, (Int) size_of_object)) ;
+
+    /* see umf_config.h for the memory allocator selection */
+    p2 = REALLOCATE (p, size) ;
+
+#if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG)
+    /* If p didn't exist on input, and p2 exists, then a new object has been
+     * allocated. */
+    if (p == (void *) NULL && p2 != (void *) NULL)
+    {
+       UMF_malloc_count++ ;
+    }
+#endif
+
+    DEBUG0 (("UMF_realloc: "ID" new malloc count "ID"\n",
+       (Int) p2, UMF_malloc_count)) ;
+
+    return (p2) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_realloc.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_realloc.h
new file mode 100644 (file)
index 0000000..376de63
--- /dev/null
@@ -0,0 +1,13 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void *UMF_realloc
+(
+    void *p,
+    Int n_objects,
+    size_t size_of_object
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_report_perm.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_report_perm.c
new file mode 100644 (file)
index 0000000..0f67f3c
--- /dev/null
@@ -0,0 +1,86 @@
+/* ========================================================================== */
+/* === UMF_report_perm ====================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+#include "umf_internal.h"
+
+#define PRINTF4U(params) { if (user || prl >= 4) PRINTF (params) ; }
+
+GLOBAL Int UMF_report_perm
+(
+    Int n,
+    const Int P [ ],
+    Int W [ ],         /* workspace of size n */
+    Int prl,
+    Int user
+)
+{
+    Int i, k, valid, prl1 ;
+
+    ASSERT (prl >= 3) ;
+
+    PRINTF4U (("permutation vector, n = "ID". ", n)) ;
+
+    if (n <= 0)
+    {
+       PRINTF (("ERROR: length of permutation is <= 0\n\n")) ;
+       return (UMFPACK_ERROR_n_nonpositive) ;
+    }
+
+    if (!P)
+    {
+       /* if P is (Int *) NULL, this is the identity permutation */
+       PRINTF (("(not present)\n\n")) ;
+       return (UMFPACK_OK) ;
+    }
+
+    if (!W)
+    {
+       PRINTF (("ERROR: out of memory\n\n")) ;
+       return (UMFPACK_ERROR_out_of_memory) ;
+    }
+
+    PRINTF4 (("\n")) ;
+
+    for (i = 0 ; i < n ; i++)
+    {
+       W [i] = TRUE ;
+    }
+
+    prl1 = prl ;
+    for (k = 0 ; k < n ; k++)
+    {
+       i = P [k] ;
+       PRINTF4 (("    "ID" : "ID" ", INDEX (k), INDEX (i))) ;
+       valid = (i >= 0 && i < n) ;
+       if (valid)
+       {
+           valid = W [i] ;
+           W [i] = FALSE ;
+       }
+       if (!valid)
+       {
+           /* out of range or duplicate entry */
+           PRINTF (("ERROR: invalid\n\n")) ;
+           return (UMFPACK_ERROR_invalid_permutation) ;
+       }
+       PRINTF4 (("\n")) ;
+       if (prl == 4 && k == 9 && n > 10)
+       {
+           PRINTF (("    ...\n")) ;
+           prl-- ;
+       }
+    }
+    prl = prl1 ;
+
+    PRINTF4 (("    permutation vector ")) ;
+    PRINTF4U (("OK\n\n")) ;
+    return (UMFPACK_OK) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_report_perm.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_report_perm.h
new file mode 100644 (file)
index 0000000..5fd7a7a
--- /dev/null
@@ -0,0 +1,15 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_report_perm
+(
+    Int n,
+    const Int P [ ],
+    Int W [ ],
+    Int prl,
+    Int user
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_report_vector.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_report_vector.c
new file mode 100644 (file)
index 0000000..d811d57
--- /dev/null
@@ -0,0 +1,119 @@
+/* ========================================================================== */
+/* === UMF_report_vector ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+#include "umf_internal.h"
+
+/* ========================================================================== */
+/* === print_value ========================================================== */
+/* ========================================================================== */
+
+PRIVATE void print_value
+(
+    Int i,
+    const double Xx [ ],
+    const double Xz [ ],
+    Int scalar             /* if true, then print real part only */
+)
+{
+    Entry *X, xi ;
+    /* if Xz is null, then X is in "merged" format (compatible with Entry, */
+    /* and ANSI C99 double _Complex type). */
+    X = (Entry *) Xx ;
+    PRINTF (("    "ID" :", INDEX (i))) ;
+    if (scalar)
+    {
+       PRINT_SCALAR (Xx [i]) ;
+    }
+    else
+    {
+       if (Xz != (double *) NULL)
+       {
+           ASSIGN (xi, Xx [i], Xz [i]) ;
+       }
+       else
+       {
+           xi = X [i] ;
+       }
+       PRINT_ENTRY (xi) ;
+    }
+    PRINTF (("\n")) ;
+}
+
+/* ========================================================================== */
+/* === UMF_report_vector ==================================================== */
+/* ========================================================================== */
+
+GLOBAL Int UMF_report_vector
+(
+    Int n,
+    const double Xx [ ],
+    const double Xz [ ],
+    Int prl,
+    Int user,
+    Int scalar
+)
+{
+    Int n2, i ;
+
+    if (user || prl >= 4)
+    {
+       PRINTF (("dense vector, n = "ID". ", n)) ;
+    }
+
+    if (user)
+    {
+       if (!Xx)
+       {
+           PRINTF (("ERROR: vector not present\n\n")) ;
+           return (UMFPACK_ERROR_argument_missing) ;
+       }
+       if (n < 0)
+       {
+           PRINTF (("ERROR: length of vector is < 0\n\n")) ;
+           return (UMFPACK_ERROR_n_nonpositive) ;
+       }
+    }
+
+    if (user || prl >= 4)
+    {
+       PRINTF4 (("\n")) ;
+    }
+
+    if (prl == 4)
+    {
+       /* print level of 4 */
+       n2 = MIN (10, n) ;
+       for (i = 0 ; i < n2 ; i++)
+       {
+           print_value (i, Xx, Xz, scalar) ;
+       }
+       if (n2 < n)
+       {
+           PRINTF (("    ...\n")) ;
+           print_value (n-1, Xx, Xz, scalar) ;
+       }
+    }
+    else if (prl > 4)
+    {
+       /* print level 4 or more */
+       for (i = 0 ; i < n ; i++)
+       {
+           print_value  (i, Xx, Xz, scalar) ;
+       }
+    }
+
+    PRINTF4 (("    dense vector ")) ;
+    if (user || prl >= 4)
+    {
+       PRINTF (("OK\n\n")) ;
+    }
+    return (UMFPACK_OK) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_report_vector.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_report_vector.h
new file mode 100644 (file)
index 0000000..9ca5ae8
--- /dev/null
@@ -0,0 +1,16 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_report_vector
+(
+    Int n,
+    const double Xx [ ],
+    const double Xz [ ],
+    Int prl,
+    Int user,
+    Int scalar
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_row_search.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_row_search.c
new file mode 100644 (file)
index 0000000..3a73a72
--- /dev/null
@@ -0,0 +1,838 @@
+/* ========================================================================== */
+/* === UMF_row_search ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Find two candidate pivot rows in a column: the best one in the front,
+    and the best one not in the front.  Return the two pivot row patterns and
+    their exact degrees.  Called by UMF_local_search.
+
+    Returns UMFPACK_OK if successful, or UMFPACK_WARNING_singular_matrix or
+    UMFPACK_ERROR_different_pattern if not.
+
+*/
+
+#include "umf_internal.h"
+#include "umf_row_search.h"
+
+GLOBAL Int UMF_row_search
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    SymbolicType *Symbolic,
+    Int cdeg0,                 /* length of column in Front */
+    Int cdeg1,                 /* length of column outside Front */
+    const Int Pattern [ ],     /* pattern of column, Pattern [0..cdeg1 -1] */
+    const Int Pos [ ],         /* Pos [Pattern [0..cdeg1 -1]] = 0..cdeg1 -1 */
+    Int pivrow [2],            /* pivrow [IN] and pivrow [OUT] */
+    Int rdeg [2],              /* rdeg [IN] and rdeg [OUT] */
+    Int W_i [ ],               /* pattern of pivrow [IN], */
+                               /* either Fcols or Woi */
+    Int W_o [ ],               /* pattern of pivrow [OUT], */
+                               /* either Wio or Woo */
+    Int prior_pivrow [2],      /* the two other rows just scanned, if any */
+    const Entry Wxy [ ],       /* numerical values Wxy [0..cdeg1-1],
+                                  either Wx or Wy */
+
+    Int pivcol,                        /* the candidate column being searched */
+    Int freebie [ ]
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    double maxval, toler, toler2, value, pivot [2] ;
+    Int i, row, deg, col, *Frpos, fnrows, *E, j, ncols, *Cols, *Rows,
+       e, f, Wrpflag, *Fcpos, fncols, tpi, max_rdeg, nans_in_col, was_offdiag,
+       diag_row, prefer_diagonal, *Wrp, found, *Diagonal_map ;
+    Tuple *tp, *tpend, *tp1, *tp2 ;
+    Unit *Memory, *p ;
+    Element *ep ;
+    Int *Row_tuples, *Row_degree, *Row_tlen ;
+
+#ifndef NDEBUG
+    Int *Col_degree ;
+    DEBUG2 (("Row_search:\n")) ;
+    for (i = 0 ; i < cdeg1 ; i++)
+    {
+       row = Pattern [i] ;
+       DEBUG4 (("   row: "ID"\n", row)) ;
+       ASSERT (row >= 0 && row < Numeric->n_row) ;
+       ASSERT (i == Pos [row]) ;
+    }
+    /* If row is not in Pattern [0..cdeg1-1], then Pos [row] == EMPTY */
+    if (UMF_debug > 0 || Numeric->n_row < 1000)
+    {
+       Int cnt = cdeg1 ;
+       DEBUG4 (("Scan all rows:\n")) ;
+       for (row = 0 ; row < Numeric->n_row ; row++)
+       {
+           if (Pos [row] < 0)
+           {
+               cnt++ ;
+           }
+           else
+           {
+               DEBUG4 (("   row: "ID" pos "ID"\n", row, Pos [row])) ;
+           }
+       }
+       ASSERT (cnt == Numeric->n_row) ;
+    }
+    Col_degree = Numeric->Cperm ;   /* for NON_PIVOTAL_COL macro only */
+    ASSERT (pivcol >= 0 && pivcol < Work->n_col) ;
+    ASSERT (NON_PIVOTAL_COL (pivcol)) ;
+#endif
+
+    pivot [IN] = 0. ;
+    pivot [OUT] = 0. ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    Row_degree = Numeric->Rperm ;
+    Row_tuples = Numeric->Uip ;
+    Row_tlen   = Numeric->Uilen ;
+    Wrp = Work->Wrp ;
+    Frpos = Work->Frpos ;
+    E = Work->E ;
+    Memory = Numeric->Memory ;
+    fnrows = Work->fnrows ;
+
+    prefer_diagonal = Symbolic->prefer_diagonal ;
+    Diagonal_map = Work->Diagonal_map ;
+
+    if (Diagonal_map)
+    {
+       diag_row = Diagonal_map [pivcol] ;
+       was_offdiag = diag_row < 0 ;
+       if (was_offdiag)
+       {
+           /* the "diagonal" entry in this column was permuted here by an
+            * earlier pivot choice.  The tighter off-diagonal tolerance will
+            * be used instead of the symmetric tolerance. */
+           diag_row = FLIP (diag_row) ;
+       }
+       ASSERT (diag_row >= 0 && diag_row < Numeric->n_row) ;
+    }
+    else
+    {
+       diag_row = EMPTY ;      /* unused */
+       was_offdiag = EMPTY ;   /* unused */
+    }
+
+    /* pivot row degree cannot exceed max_rdeg */
+    max_rdeg = Work->fncols_max ;
+
+    /* ---------------------------------------------------------------------- */
+    /* scan pivot column for candidate rows */
+    /* ---------------------------------------------------------------------- */
+
+    maxval = 0.0 ;
+    nans_in_col = FALSE ;
+
+    for (i = 0 ; i < cdeg1 ; i++)
+    {
+       APPROX_ABS (value, Wxy [i]) ;
+       if (SCALAR_IS_NAN (value))
+       {
+           nans_in_col = TRUE ;
+           maxval = value ;
+           break ;
+       }
+       /* This test can now ignore the NaN case: */
+       maxval = MAX (maxval, value) ;
+    }
+
+    /* if maxval is zero, the matrix is numerically singular */
+
+    toler = Numeric->relpt * maxval ;
+    toler2 = Numeric->relpt2 * maxval ;
+    toler2 = was_offdiag ? toler : toler2 ;
+
+    DEBUG5 (("Row_search begins [ maxval %g toler %g %g\n",
+       maxval, toler, toler2)) ;
+    if (SCALAR_IS_NAN (toler) || SCALAR_IS_NAN (toler2))
+    {
+       nans_in_col = TRUE ;
+    }
+
+    if (!nans_in_col)
+    {
+
+       /* look for the diagonal entry, if it exists */
+       found = FALSE ;
+       ASSERT (!SCALAR_IS_NAN (toler)) ;
+
+       if (prefer_diagonal)
+       {
+           ASSERT (diag_row != EMPTY) ;
+           i = Pos [diag_row] ;
+           if (i >= 0)
+           {
+               double a ;
+               ASSERT (i < cdeg1) ;
+               ASSERT (diag_row == Pattern [i]) ;
+
+               APPROX_ABS (a, Wxy [i]) ;
+
+               ASSERT (!SCALAR_IS_NAN (a)) ;
+               ASSERT (!SCALAR_IS_NAN (toler2)) ;
+
+               if (SCALAR_IS_NONZERO (a) && a >= toler2)
+               {
+                   /* found it! */
+                   DEBUG3 (("Symmetric pivot: "ID" "ID"\n", pivcol, diag_row));
+                   found = TRUE ;
+                   if (Frpos [diag_row] >= 0 && Frpos [diag_row] < fnrows)
+                   {
+                       pivrow [IN] = diag_row ;
+                       pivrow [OUT] = EMPTY ;
+                   }
+                   else
+                   {
+                       pivrow [IN] = EMPTY ;
+                       pivrow [OUT] = diag_row ;
+                   }
+               }
+           }
+       }
+
+       /* either no diagonal found, or we didn't look for it */
+       if (!found)
+       {
+           if (cdeg0 > 0)
+           {
+
+               /* this is a column in the front */
+               for (i = 0 ; i < cdeg0 ; i++)
+               {
+                   double a ;
+                   APPROX_ABS (a, Wxy [i]) ;
+                   ASSERT (!SCALAR_IS_NAN (a)) ;
+                   ASSERT (!SCALAR_IS_NAN (toler)) ;
+                   if (SCALAR_IS_NONZERO (a) && a >= toler)
+                   {
+                       row = Pattern [i] ;
+                       deg = Row_degree [row] ;
+#ifndef NDEBUG
+                       DEBUG6 ((ID" candidate row "ID" deg "ID" absval %g\n",
+                           i, row, deg, a)) ;
+                       UMF_dump_rowcol (0, Numeric, Work, row, TRUE) ;
+#endif
+                       ASSERT (Frpos [row] >= 0 && Frpos [row] < fnrows) ;
+                       ASSERT (Frpos [row] == i) ;
+                       /* row is in the current front */
+                       DEBUG4 ((" in front\n")) ;
+                       if (deg < rdeg [IN]
+                           /* break ties by picking the largest entry: */
+                              || (deg == rdeg [IN] && a > pivot [IN])
+                           /* break ties by picking the diagonal entry: */
+                           /* || (deg == rdeg [IN] && row == diag_row) */
+                          )
+                       {
+                           /* best row in front, so far */
+                           pivrow [IN] = row ;
+                           rdeg [IN] = deg ;
+                           pivot [IN] = a ;
+                       }
+                   }
+               }
+               for ( ; i < cdeg1 ; i++)
+               {
+                   double a ;
+                   APPROX_ABS (a, Wxy [i]) ;
+                   ASSERT (!SCALAR_IS_NAN (a)) ;
+                   ASSERT (!SCALAR_IS_NAN (toler)) ;
+                   if (SCALAR_IS_NONZERO (a) && a >= toler)
+                   {
+                       row = Pattern [i] ;
+                       deg = Row_degree [row] ;
+#ifndef NDEBUG
+                       DEBUG6 ((ID" candidate row "ID" deg "ID" absval %g\n",
+                           i, row, deg, a)) ;
+                       UMF_dump_rowcol (0, Numeric, Work, row, TRUE) ;
+#endif
+                       ASSERT (Frpos [row] == i) ;
+                       /* row is not in the current front */
+                       DEBUG4 ((" NOT in front\n")) ;
+                       if (deg < rdeg [OUT]
+                           /* break ties by picking the largest entry: */
+                              || (deg == rdeg [OUT] && a > pivot [OUT])
+                           /* break ties by picking the diagonal entry: */
+                           /* || (deg == rdeg [OUT] && row == diag_row) */
+                          )
+                       {
+                           /* best row not in front, so far */
+                           pivrow [OUT] = row ;
+                           rdeg [OUT] = deg ;
+                           pivot [OUT] = a ;
+                       }
+                   }
+               }
+
+           }
+           else
+           {
+
+               /* this column is not in the front */
+               for (i = 0 ; i < cdeg1 ; i++)
+               {
+                   double a ;
+                   APPROX_ABS (a, Wxy [i]) ;
+                   ASSERT (!SCALAR_IS_NAN (a)) ;
+                   ASSERT (!SCALAR_IS_NAN (toler)) ;
+                   if (SCALAR_IS_NONZERO (a) && a >= toler)
+                   {
+                       row = Pattern [i] ;
+                       deg = Row_degree [row] ;
+#ifndef NDEBUG
+                       DEBUG6 ((ID" candidate row "ID" deg "ID" absval %g\n",
+                           i, row, deg, a)) ;
+                       UMF_dump_rowcol (0, Numeric, Work, row, TRUE) ;
+#endif
+                       if (Frpos [row] >= 0 && Frpos [row] < fnrows)
+                       {
+                           /* row is in the current front */
+                           DEBUG4 ((" in front\n")) ;
+                           if (deg < rdeg [IN]
+                           /* break ties by picking the largest entry: */
+                              || (deg == rdeg [IN] && a > pivot [IN])
+                           /* break ties by picking the diagonal entry: */
+                           /* || (deg == rdeg [IN] && row == diag_row) */
+                              )
+                           {
+                               /* best row in front, so far */
+                               pivrow [IN] = row ;
+                               rdeg [IN] = deg ;
+                               pivot [IN] = a ;
+                           }
+                       }
+                       else
+                       {
+                           /* row is not in the current front */
+                           DEBUG4 ((" NOT in front\n")) ;
+                           if (deg < rdeg [OUT]
+                           /* break ties by picking the largest entry: */
+                              || (deg == rdeg[OUT] && a > pivot [OUT])
+                           /* break ties by picking the diagonal entry: */
+                           /* || (deg == rdeg[OUT] && row == diag_row) */
+                              )
+                           {
+                               /* best row not in front, so far */
+                               pivrow [OUT] = row ;
+                               rdeg [OUT] = deg ;
+                               pivot [OUT] = a ;
+                           }
+                       }
+                   }
+               }
+           }
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* NaN handling */
+    /* ---------------------------------------------------------------------- */
+
+    /* if cdeg1 > 0 then we must have found a pivot row ... unless NaN's */
+    /* exist.  Try with no numerical tests if no pivot found. */
+
+    if (cdeg1 > 0 && pivrow [IN] == EMPTY && pivrow [OUT] == EMPTY)
+    {
+       /* cleanup for the NaN case */
+       DEBUG0 (("Found a NaN in pivot column!\n")) ;
+
+       /* grab the first entry in the pivot column, ignoring degree, */
+       /* numerical stability, and symmetric preference */
+       row = Pattern [0] ;
+       deg = Row_degree [row] ;
+       if (Frpos [row] >= 0 && Frpos [row] < fnrows)
+       {
+           /* row is in the current front */
+           DEBUG4 ((" in front\n")) ;
+           pivrow [IN] = row ;
+           rdeg [IN] = deg ;
+       }
+       else
+       {
+           /* row is not in the current front */
+           DEBUG4 ((" NOT in front\n")) ;
+           pivrow [OUT] = row ;
+           rdeg [OUT] = deg ;
+       }
+
+       /* We are now guaranteed to have a pivot, no matter how broken */
+       /* (non-IEEE compliant) the underlying numerical operators are. */
+       /* This is particularly a problem for Microsoft compilers (they do */
+       /* not handle NaN's properly). Now try to find a sparser pivot, if */
+       /* possible. */
+
+       for (i = 1 ; i < cdeg1 ; i++)
+       {
+           row = Pattern [i] ;
+           deg = Row_degree [row] ;
+
+           if (Frpos [row] >= 0 && Frpos [row] < fnrows)
+           {
+               /* row is in the current front */
+               DEBUG4 ((" in front\n")) ;
+               if (deg < rdeg [IN] || (deg == rdeg [IN] && row == diag_row))
+               {
+                   /* best row in front, so far */
+                   pivrow [IN] = row ;
+                   rdeg [IN] = deg ;
+               }
+           }
+           else
+           {
+               /* row is not in the current front */
+               DEBUG4 ((" NOT in front\n")) ;
+               if (deg < rdeg [OUT] || (deg == rdeg [OUT] && row == diag_row))
+               {
+                   /* best row not in front, so far */
+                   pivrow [OUT] = row ;
+                   rdeg [OUT] = deg ;
+               }
+           }
+       }
+    }
+
+    /* We found a pivot if there are entries (even zero ones) in pivot col */
+    ASSERT (IMPLIES (cdeg1 > 0, pivrow[IN] != EMPTY || pivrow[OUT] != EMPTY)) ;
+
+    /* If there are no entries in the pivot column, then no pivot is found */
+    ASSERT (IMPLIES (cdeg1 == 0, pivrow[IN] == EMPTY && pivrow[OUT] == EMPTY)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check for singular matrix */
+    /* ---------------------------------------------------------------------- */
+
+    if (cdeg1  == 0)
+    {
+       if (fnrows > 0)
+       {
+           /*
+               Get the pivrow [OUT][IN] from the current front.
+               The frontal matrix looks like this:
+
+                       pivcol[OUT]
+                       |
+                       v
+               x x x x 0   <- so grab this row as the pivrow [OUT][IN].
+               x x x x 0
+               x x x x 0
+               0 0 0 0 0
+
+               The current frontal matrix has some rows in it.  The degree
+               of the pivcol[OUT] is zero.  The column is empty, and the
+               current front does not contribute to it.
+
+           */
+           pivrow [IN] = Work->Frows [0] ;
+           DEBUGm4 (("Got zero pivrow[OUT][IN] "ID" from current front\n",
+               pivrow [IN])) ;
+       }
+       else
+       {
+
+           /*
+               Get a pivot row from the row-merge tree, use as
+               pivrow [OUT][OUT].   pivrow [IN] remains EMPTY.
+               This can only happen if the current front is 0-by-0.
+           */
+
+           Int *Front_leftmostdesc, *Front_1strow, *Front_new1strow, row1,
+               row2, fleftmost, nfr, n_row, frontid ;
+
+           ASSERT (Work->fncols == 0) ;
+
+           Front_leftmostdesc = Symbolic->Front_leftmostdesc ;
+           Front_1strow = Symbolic->Front_1strow ;
+           Front_new1strow = Work->Front_new1strow ;
+           nfr = Symbolic->nfr ;
+           n_row = Numeric->n_row ;
+           frontid = Work->frontid ;
+
+           DEBUGm4 (("Note: pivcol: "ID" is empty front "ID"\n",
+               pivcol, frontid)) ;
+#ifndef NDEBUG
+           DEBUG1 (("Calling dump rowmerge\n")) ;
+           UMF_dump_rowmerge (Numeric, Symbolic, Work) ;
+#endif
+
+           /* Row-merge set is the non-pivotal rows in the range */
+           /* Front_new1strow [Front_leftmostdesc [frontid]] to */
+           /* Front_1strow [frontid+1] - 1. */
+           /* If this is empty, then use the empty rows, in the range */
+           /* Front_new1strow [nfr] to n_row-1. */
+           /* If this too is empty, then pivrow [OUT] will be empty. */
+           /* In both cases, update Front_new1strow [...]. */
+
+           fleftmost = Front_leftmostdesc [frontid] ;
+           row1 = Front_new1strow [fleftmost] ;
+           row2 = Front_1strow [frontid+1] - 1 ;
+           DEBUG1 (("Leftmost: "ID" Rows ["ID" to "ID"] srch ["ID" to "ID"]\n",
+               fleftmost, Front_1strow [frontid], row2, row1, row2)) ;
+
+           /* look in the range row1 ... row2 */
+           for (row = row1 ; row <= row2 ; row++)
+           {
+               DEBUG3 (("   Row: "ID"\n", row)) ;
+               if (NON_PIVOTAL_ROW (row))
+               {
+                   /* found it */
+                   DEBUG3 (("   Row: "ID" found\n", row)) ;
+                   ASSERT (Frpos [row] == EMPTY) ;
+                   pivrow [OUT] = row ;
+                   DEBUGm4 (("got row merge pivrow %d\n", pivrow [OUT])) ;
+                   break ;
+               }
+           }
+           Front_new1strow [fleftmost] = row ;
+
+           if (pivrow [OUT] == EMPTY)
+           {
+               /* not found, look in empty row set in "dummy" front */
+               row1 = Front_new1strow [nfr] ;
+               row2 = n_row-1 ;
+               DEBUG3 (("Empty: "ID" Rows ["ID" to "ID"] srch["ID" to "ID"]\n",
+                   nfr, Front_1strow [nfr], row2, row1, row2)) ;
+
+               /* look in the range row1 ... row2 */
+               for (row = row1 ; row <= row2 ; row++)
+               {
+                   DEBUG3 (("   Empty Row: "ID"\n", row)) ;
+                   if (NON_PIVOTAL_ROW (row))
+                   {
+                       /* found it */
+                       DEBUG3 (("   Empty Row: "ID" found\n", row)) ;
+                       ASSERT (Frpos [row] == EMPTY) ;
+                       pivrow [OUT] = row ;
+                       DEBUGm4 (("got dummy row pivrow %d\n", pivrow [OUT])) ;
+                       break ;
+                   }
+               }
+               Front_new1strow [nfr] = row ;
+           }
+
+           if (pivrow [OUT] == EMPTY)
+           {
+               /* Row-merge set is empty.  We can just discard */
+               /* the candidate pivot column. */
+               DEBUG0 (("Note: row-merge set empty\n")) ;
+               DEBUGm4 (("got no pivrow \n")) ;
+               return (UMFPACK_WARNING_singular_matrix) ;
+           }
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the candidate row in the front, if any */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    /* check Wrp */
+    ASSERT (Work->Wrpflag > 0) ;
+    if (UMF_debug > 0 || Work->n_col < 1000)
+    {
+       for (i = 0 ; i < Work->n_col ; i++)
+       {
+           ASSERT (Wrp [i] < Work->Wrpflag) ;
+       }
+    }
+#endif
+
+#ifndef NDEBUG
+    DEBUG4 (("pivrow [IN]: "ID"\n", pivrow [IN])) ;
+    UMF_dump_rowcol (0, Numeric, Work, pivrow [IN], TRUE) ;
+#endif
+
+    if (pivrow [IN] != EMPTY)
+    {
+
+       /* the row merge candidate row is not pivrow [IN] */
+       freebie [IN] = (pivrow [IN] == prior_pivrow [IN]) && (cdeg1  > 0) ;
+       ASSERT (cdeg1  >= 0) ;
+
+       if (!freebie [IN])
+       {
+           /* include current front in the degree of this row */
+
+           Fcpos = Work->Fcpos ;
+           fncols = Work->fncols ;
+
+           Wrpflag = Work->Wrpflag ;
+
+           /* -------------------------------------------------------------- */
+           /* construct the pattern of the IN row */
+           /* -------------------------------------------------------------- */
+
+#ifndef NDEBUG
+           /* check Fcols */
+           DEBUG5 (("ROW ASSEMBLE: rdeg "ID"\nREDUCE ROW "ID"\n",
+               fncols, pivrow [IN])) ;
+           for (j = 0 ; j < fncols ; j++)
+           {
+               col = Work->Fcols [j] ;
+               ASSERT (col >= 0 && col < Work->n_col) ;
+               ASSERT (Fcpos [col] >= 0) ;
+           }
+           if (UMF_debug > 0 || Work->n_col < 1000)
+           {
+               Int cnt = fncols ;
+               for (col = 0 ; col < Work->n_col ; col++)
+               {
+                   if (Fcpos [col] < 0) cnt++ ;
+               }
+               ASSERT (cnt == Work->n_col) ;
+           }
+#endif
+
+           rdeg [IN] = fncols ;
+
+           ASSERT (pivrow [IN] >= 0 && pivrow [IN] < Work->n_row) ;
+           ASSERT (NON_PIVOTAL_ROW (pivrow [IN])) ;
+
+           /* add the pivot column itself */
+           ASSERT (Wrp [pivcol] != Wrpflag) ;
+           if (Fcpos [pivcol] < 0)
+           {
+               DEBUG3 (("Adding pivot col to pivrow [IN] pattern\n")) ;
+               if (rdeg [IN] >= max_rdeg)
+               {
+                   /* :: pattern change (in) :: */
+                   return (UMFPACK_ERROR_different_pattern) ;
+               }
+               Wrp [pivcol] = Wrpflag ;
+               W_i [rdeg [IN]++] = pivcol ;
+           }
+
+           tpi = Row_tuples [pivrow [IN]] ;
+           if (tpi)
+           {
+               tp = (Tuple *) (Memory + tpi) ;
+               tp1 = tp ;
+               tp2 = tp ;
+               tpend = tp + Row_tlen [pivrow [IN]] ;
+               for ( ; tp < tpend ; tp++)
+               {
+                   e = tp->e ;
+                   ASSERT (e > 0 && e <= Work->nel) ;
+                   if (!E [e])
+                   {
+                       continue ;      /* element already deallocated */
+                   }
+                   f = tp->f ;
+                   p = Memory + E [e] ;
+                   ep = (Element *) p ;
+                   p += UNITS (Element, 1) ;
+                   Cols = (Int *) p ;
+                   ncols = ep->ncols ;
+                   Rows = Cols + ncols ;
+                   if (Rows [f] == EMPTY)
+                   {
+                       continue ;      /* row already assembled */
+                   }
+                   ASSERT (pivrow [IN] == Rows [f]) ;
+
+                   for (j = 0 ; j < ncols ; j++)
+                   {
+                       col = Cols [j] ;
+                       ASSERT (col >= EMPTY && col < Work->n_col) ;
+                       if ((col >= 0) && (Wrp [col] != Wrpflag)
+                           && Fcpos [col] <0)
+                       {
+                           ASSERT (NON_PIVOTAL_COL (col)) ;
+                           if (rdeg [IN] >= max_rdeg)
+                           {
+                               /* :: pattern change (rdeg in failure) :: */
+                               DEBUGm4 (("rdeg [IN] >= max_rdeg failure\n")) ;
+                               return (UMFPACK_ERROR_different_pattern) ;
+                           }
+                           Wrp [col] = Wrpflag ;
+                           W_i [rdeg [IN]++] = col ;
+                       }
+                   }
+
+                   *tp2++ = *tp ;      /* leave the tuple in the list */
+               }
+               Row_tlen [pivrow [IN]] = tp2 - tp1 ;
+           }
+
+#ifndef NDEBUG
+           DEBUG4 (("Reduced IN row:\n")) ;
+           for (j = 0 ; j < fncols ; j++)
+           {
+               DEBUG6 ((" "ID" "ID" "ID"\n",
+                   j, Work->Fcols [j], Fcpos [Work->Fcols [j]])) ;
+               ASSERT (Fcpos [Work->Fcols [j]] >= 0) ;
+           }
+           for (j = fncols ; j < rdeg [IN] ; j++)
+           {
+               DEBUG6 ((" "ID" "ID" "ID"\n", j, W_i [j], Wrp [W_i [j]]));
+               ASSERT (W_i [j] >= 0 && W_i [j] < Work->n_col) ;
+               ASSERT (Wrp [W_i [j]] == Wrpflag) ;
+           }
+           /* mark the end of the pattern in case we scan it by mistake */
+           /* Note that this means W_i must be of size >= fncols_max + 1 */
+           W_i [rdeg [IN]] = EMPTY ;
+#endif
+
+           /* rdeg [IN] is now the exact degree of the IN row */
+
+           /* clear Work->Wrp. */
+           Work->Wrpflag++ ;
+           /* All Wrp [0..n_col] is now < Wrpflag */
+       }
+    }
+
+#ifndef NDEBUG
+    /* check Wrp */
+    if (UMF_debug > 0 || Work->n_col < 1000)
+    {
+       for (i = 0 ; i < Work->n_col ; i++)
+       {
+           ASSERT (Wrp [i] < Work->Wrpflag) ;
+       }
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the candidate row not in the front, if any */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    DEBUG4 (("pivrow [OUT]: "ID"\n", pivrow [OUT])) ;
+    UMF_dump_rowcol (0, Numeric, Work, pivrow [OUT], TRUE) ;
+#endif
+
+    /* If this is a candidate row from the row merge set, force it to be */
+    /* scanned (ignore prior_pivrow [OUT]). */
+
+    if (pivrow [OUT] != EMPTY)
+    {
+       freebie [OUT] = (pivrow [OUT] == prior_pivrow [OUT]) && cdeg1  > 0 ;
+       ASSERT (cdeg1  >= 0) ;
+
+       if (!freebie [OUT])
+       {
+
+           Wrpflag = Work->Wrpflag ;
+
+           /* -------------------------------------------------------------- */
+           /* construct the pattern of the row */
+           /* -------------------------------------------------------------- */
+
+           rdeg [OUT] = 0 ;
+
+           ASSERT (pivrow [OUT] >= 0 && pivrow [OUT] < Work->n_row) ;
+           ASSERT (NON_PIVOTAL_ROW (pivrow [OUT])) ;
+
+           /* add the pivot column itself */
+           ASSERT (Wrp [pivcol] != Wrpflag) ;
+           DEBUG3 (("Adding pivot col to pivrow [OUT] pattern\n")) ;
+           if (rdeg [OUT] >= max_rdeg)
+           {
+               /* :: pattern change (out) :: */
+               return (UMFPACK_ERROR_different_pattern) ;
+           }
+           Wrp [pivcol] = Wrpflag ;
+           W_o [rdeg [OUT]++] = pivcol ;
+
+           tpi = Row_tuples [pivrow [OUT]] ;
+           if (tpi)
+           {
+               tp = (Tuple *) (Memory + tpi) ;
+               tp1 = tp ;
+               tp2 = tp ;
+               tpend = tp + Row_tlen [pivrow [OUT]] ;
+               for ( ; tp < tpend ; tp++)
+               {
+                   e = tp->e ;
+                   ASSERT (e > 0 && e <= Work->nel) ;
+                   if (!E [e])
+                   {
+                       continue ;      /* element already deallocated */
+                   }
+                   f = tp->f ;
+                   p = Memory + E [e] ;
+                   ep = (Element *) p ;
+                   p += UNITS (Element, 1) ;
+                   Cols = (Int *) p ;
+                   ncols = ep->ncols ;
+                   Rows = Cols + ncols ;
+                   if (Rows [f] == EMPTY)
+                   {
+                       continue ;      /* row already assembled */
+                   }
+                   ASSERT (pivrow [OUT] == Rows [f]) ;
+
+                   for (j = 0 ; j < ncols ; j++)
+                   {
+                       col = Cols [j] ;
+                       ASSERT (col >= EMPTY && col < Work->n_col) ;
+                       if ((col >= 0) && (Wrp [col] != Wrpflag))
+                       {
+                           ASSERT (NON_PIVOTAL_COL (col)) ;
+                           if (rdeg [OUT] >= max_rdeg)
+                           {
+                               /* :: pattern change (rdeg out failure) :: */
+                               DEBUGm4 (("rdeg [OUT] failure\n")) ;
+                               return (UMFPACK_ERROR_different_pattern) ;
+                           }
+                           Wrp [col] = Wrpflag ;
+                           W_o [rdeg [OUT]++] = col ;
+                       }
+                   }
+                   *tp2++ = *tp ;      /* leave the tuple in the list */
+               }
+               Row_tlen [pivrow [OUT]] = tp2 - tp1 ;
+           }
+
+#ifndef NDEBUG
+           DEBUG4 (("Reduced row OUT:\n")) ;
+           for (j = 0 ; j < rdeg [OUT] ; j++)
+           {
+               DEBUG6 ((" "ID" "ID" "ID"\n", j, W_o [j], Wrp [W_o [j]])) ;
+               ASSERT (W_o [j] >= 0 && W_o [j] < Work->n_col) ;
+               ASSERT (Wrp [W_o [j]] == Wrpflag) ;
+           }
+           /* mark the end of the pattern in case we scan it by mistake */
+           /* Note that this means W_o must be of size >= fncols_max + 1 */
+           W_o [rdeg [OUT]] = EMPTY ;
+#endif
+
+           /* rdeg [OUT] is now the exact degree of the row */
+
+           /* clear Work->Wrp. */
+           Work->Wrpflag++ ;
+           /* All Wrp [0..n] is now < Wrpflag */
+
+       }
+
+    }
+    DEBUG5 (("Row_search end ] \n")) ;
+
+#ifndef NDEBUG
+    /* check Wrp */
+    if (UMF_debug > 0 || Work->n_col < 1000)
+    {
+       for (i = 0 ; i < Work->n_col ; i++)
+       {
+           ASSERT (Wrp [i] < Work->Wrpflag) ;
+       }
+    }
+#endif
+
+    return (UMFPACK_OK) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_row_search.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_row_search.h
new file mode 100644 (file)
index 0000000..9490c87
--- /dev/null
@@ -0,0 +1,33 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_row_search
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    SymbolicType *Symbolic,
+    Int cdeg0,
+    Int cdeg1,
+    const Int Pattern [ ],
+    const Int Pos [ ],
+    Int pivrow [2],
+    Int rdeg [2],
+    Int W_i [ ],
+    Int W_o [ ],
+    Int prior_pivrow [2],
+    const Entry Wxy [ ],
+    Int pivcol,
+    Int freebie [2]
+) ;
+
+#define IN 0
+#define OUT 1
+
+#define IN_IN 0
+#define IN_OUT 1
+#define OUT_IN 2
+#define OUT_OUT 3
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_scale.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_scale.c
new file mode 100644 (file)
index 0000000..b07654f
--- /dev/null
@@ -0,0 +1,128 @@
+/* ========================================================================== */
+/* === UMF_scale ============================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* Divide a vector of stride 1 by the pivot value. */
+
+#include "umf_internal.h"
+
+GLOBAL void UMF_scale
+(
+    Int n,
+    Entry pivot,
+    Entry X [ ]
+)
+{
+    Int i ;
+    Entry x ;
+    double s ;
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the approximate absolute value of the pivot, and select method */
+    /* ---------------------------------------------------------------------- */
+
+    APPROX_ABS (s, pivot) ;
+
+    if (s < RECIPROCAL_TOLERANCE || IS_NAN (pivot))
+    {
+       /* ------------------------------------------------------------------ */
+       /* tiny, or zero, pivot case */
+       /* ------------------------------------------------------------------ */
+
+       /* The pivot is tiny, or NaN.  Do not divide zero by the pivot value,
+        * and do not multiply by 1/pivot, either. */
+
+       for (i = 0 ; i < n ; i++)
+       {
+           /* X [i] /= pivot ; */
+           x = X [i] ;
+
+#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.  select the x/pivot or x * (1/pivot) method */
+       /* ------------------------------------------------------------------ */
+
+       /* The pivot is not tiny, and is not NaN.   Don't bother to check for
+        * zeros in the pivot column, X. */
+
+#if !defined (NRECIPROCAL) && !(defined (__GNUC__) && defined (COMPLEX))
+
+           /* -------------------------------------------------------------- */
+           /* multiply x by (1/pivot) */
+           /* -------------------------------------------------------------- */
+
+           /* Slightly less accurate, but faster.  It allows the use of
+            * the level-1 BLAS dscal or zscal routine.  This not used when
+            * UMFPACK is used in MATLAB (either as a built-in routine, or as
+            * a mexFunction).
+            *
+            * Using gcc version 3.2 can cause the following code to fail for
+            * some complex matrices (not all), with or without the BLAS.  This
+            * was found in Red Hat Linux 7.3 on a Dell Latitude C840 with a
+            * Pentium 4M.  Thus, this code is not used when gcc is used, for
+            * the complex case.
+            *
+            * It works just fine with Intel's icc compiler, version 7.0.
+            */
+
+           /* pivot = 1 / pivot */
+           RECIPROCAL (pivot) ;
+
+#if defined (USE_NO_BLAS)
+           for (i = 0 ; i < n ; i++)
+           {
+               /* X [i] *= pivot ; */
+               x = X [i] ;
+               MULT (X [i], x, pivot) ;
+           }
+#else
+           BLAS_SCAL (n, pivot, X) ;
+#endif
+
+#else
+
+           /* -------------------------------------------------------------- */
+           /* divide x by the pivot */
+           /* -------------------------------------------------------------- */
+
+           /* This is slightly more accurate, particularly if the pivot column
+            * consists of only IEEE subnormals.  Always do this if UMFPACK is
+            * being compiled as a built-in routine or mexFunction in MATLAB,
+            * or if gcc is being used with complex matrices. */
+
+           for (i = 0 ; i < n ; i++)
+           {
+               /* X [i] /= pivot ; */
+               x = X [i] ;
+               DIV (X [i], x, pivot) ;
+           }
+
+#endif
+
+    }
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_scale.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_scale.h
new file mode 100644 (file)
index 0000000..74967a0
--- /dev/null
@@ -0,0 +1,13 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_scale
+(
+    Int n,
+    Entry alpha,
+    Entry X [ ]
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_scale_column.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_scale_column.c
new file mode 100644 (file)
index 0000000..2c47898
--- /dev/null
@@ -0,0 +1,434 @@
+/* ========================================================================== */
+/* === UMF_scale_column ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Scale the current pivot column, move the pivot row and column into place,
+    and log the permutation.
+*/
+
+#include "umf_internal.h"
+#include "umf_mem_free_tail_block.h"
+#include "umf_scale.h"
+
+/* ========================================================================== */
+/* === shift_pivot_row ====================================================== */
+/* ========================================================================== */
+
+/* Except for the BLAS, most of the time is typically spent in the following
+ * shift_pivot_row routine.  It copies the pivot row into the U block, and
+ * then fills in the whole in the C block by shifting the last row of C into
+ * the row vacated by the pivot row.
+ */
+
+PRIVATE void shift_pivot_row (Entry *Fd, Entry *Fs, Entry *Fe, Int len, Int d)
+{
+    Int j ;
+#pragma ivdep
+    for (j = 0 ; j < len ; j++)
+    {
+       Fd [j]   = Fs [j*d] ;
+       Fs [j*d] = Fe [j*d] ;
+    }
+}
+
+/* ========================================================================== */
+/* === UMF_scale_column ===================================================== */
+/* ========================================================================== */
+
+GLOBAL void UMF_scale_column
+(
+    NumericType *Numeric,
+    WorkType *Work
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int k, k1, fnr_curr, fnrows, fncols, *Frpos, *Fcpos, pivrow, pivcol,
+       *Frows, *Fcols, fnc_curr, fnpiv, *Row_tuples, nb,
+       *Col_tuples, *Rperm, *Cperm, fspos, col2, row2 ;
+    Entry pivot_value, *Fcol,
+       *Flublock, *Flblock, *Fublock, *Fcblock ;
+#ifndef NDEBUG
+    Int *Col_degree, *Row_degree ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    fnrows = Work->fnrows ;
+    fncols = Work->fncols ;
+    fnpiv = Work->fnpiv ;
+
+    /* ---------------------------------------------------------------------- */
+
+    Rperm = Numeric->Rperm ;
+    Cperm = Numeric->Cperm ;
+
+    /* ---------------------------------------------------------------------- */
+
+    Flublock = Work->Flublock ;
+    Flblock  = Work->Flblock ;
+    Fublock  = Work->Fublock ;
+    Fcblock  = Work->Fcblock ;
+
+    fnr_curr = Work->fnr_curr ;
+    fnc_curr = Work->fnc_curr ;
+    Frpos = Work->Frpos ;
+    Fcpos = Work->Fcpos ;
+    Frows = Work->Frows ;
+    Fcols = Work->Fcols ;
+    pivrow = Work->pivrow ;
+    pivcol = Work->pivcol ;
+
+    ASSERT (pivrow >= 0 && pivrow < Work->n_row) ;
+    ASSERT (pivcol >= 0 && pivcol < Work->n_col) ;
+
+#ifndef NDEBUG
+    Col_degree = Numeric->Cperm ;      /* for NON_PIVOTAL_COL macro */
+    Row_degree = Numeric->Rperm ;      /* for NON_PIVOTAL_ROW macro */
+#endif
+
+    Row_tuples = Numeric->Uip ;
+    Col_tuples = Numeric->Lip ;
+    nb = Work->nb ;
+
+#ifndef NDEBUG
+    ASSERT (fnrows == Work->fnrows_new + 1) ;
+    ASSERT (fncols == Work->fncols_new + 1) ;
+    DEBUG1 (("SCALE COL: fnrows "ID" fncols "ID"\n", fnrows, fncols)) ;
+    DEBUG2 (("\nFrontal matrix, including all space:\n"
+               "fnr_curr "ID" fnc_curr "ID" nb    "ID"\n"
+               "fnrows   "ID" fncols   "ID" fnpiv "ID"\n",
+               fnr_curr, fnc_curr, nb, fnrows, fncols, fnpiv)) ;
+    DEBUG2 (("\nJust the active part:\n")) ;
+    DEBUG7 (("C  block: ")) ;
+    UMF_dump_dense (Fcblock,  fnr_curr, fnrows, fncols) ;
+    DEBUG7 (("L  block: ")) ;
+    UMF_dump_dense (Flblock,  fnr_curr, fnrows, fnpiv);
+    DEBUG7 (("U' block: ")) ;
+    UMF_dump_dense (Fublock,  fnc_curr, fncols, fnpiv) ;
+    DEBUG7 (("LU block: ")) ;
+    UMF_dump_dense (Flublock, nb, fnpiv, fnpiv) ;
+#endif
+
+    /* ====================================================================== */
+    /* === Shift pivot row and column ======================================= */
+    /* ====================================================================== */
+
+    /* ---------------------------------------------------------------------- */
+    /* move pivot column into place */
+    /* ---------------------------------------------------------------------- */
+
+    /* Note that the pivot column is already in place.  Just shift the last
+     * column into the position vacated by the pivot column. */
+
+    fspos = Fcpos [pivcol] ;
+
+    /* one less column in the contribution block */
+    fncols = --(Work->fncols) ;
+
+    if (fspos != fncols * fnr_curr)
+    {
+
+       Int fs = fspos / fnr_curr ;
+
+       DEBUG6 (("Shift pivot column in front\n")) ;
+       DEBUG6 (("fspos: "ID" flpos: "ID"\n", fspos, fncols * fnr_curr)) ;
+
+       /* ------------------------------------------------------------------ */
+       /* move Fe => Fs */
+       /* ------------------------------------------------------------------ */
+
+       /* column of the contribution block: */
+       {
+           /* Fs: current position of pivot column in contribution block */
+           /* Fe: position of last column in contribution block */
+           Int i ;
+           Entry *Fs, *Fe ;
+           Fs = Fcblock + fspos ;
+           Fe = Fcblock + fncols * fnr_curr ;
+#pragma ivdep
+           for (i = 0 ; i < fnrows ; i++)
+           {
+               Fs [i] = Fe [i] ;
+           }
+       }
+
+       /* column of the U2 block */
+       {
+           /* Fs: current position of pivot column in U block */
+           /* Fe: last column in U block */
+           Int i ;
+           Entry *Fs, *Fe ;
+           Fs = Fublock + fs ;
+           Fe = Fublock + fncols ;
+#pragma ivdep
+           for (i = 0 ; i < fnpiv ; i++)
+           {
+               Fs [i * fnc_curr] = Fe [i * fnc_curr] ;
+           }
+       }
+
+       /* move column Fe to Fs in the Fcols pattern */
+       col2 = Fcols [fncols] ;
+       Fcols [fs] = col2 ;
+       Fcpos [col2] = fspos ;
+    }
+
+    /* pivot column is no longer in the frontal matrix */
+    Fcpos [pivcol] = EMPTY ;
+
+#ifndef NDEBUG
+    DEBUG2 (("\nFrontal matrix after col swap, including all space:\n"
+               "fnr_curr "ID" fnc_curr "ID" nb    "ID"\n"
+               "fnrows   "ID" fncols   "ID" fnpiv "ID"\n",
+               fnr_curr, fnc_curr, nb,
+               fnrows, fncols, fnpiv)) ;
+    DEBUG2 (("\nJust the active part:\n")) ;
+    DEBUG7 (("C  block: ")) ;
+    UMF_dump_dense (Fcblock,  fnr_curr, fnrows, fncols) ;
+    DEBUG7 (("L  block: ")) ;
+    UMF_dump_dense (Flblock,  fnr_curr, fnrows, fnpiv+1);
+    DEBUG7 (("U' block: ")) ;
+    UMF_dump_dense (Fublock,  fnc_curr, fncols, fnpiv) ;
+    DEBUG7 (("LU block: ")) ;
+    UMF_dump_dense (Flublock, nb, fnpiv, fnpiv+1) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* move pivot row into place */
+    /* ---------------------------------------------------------------------- */
+
+    fspos = Frpos [pivrow] ;
+
+    /* one less row in the contribution block */
+    fnrows = --(Work->fnrows) ;
+
+    DEBUG6 (("Swap/shift pivot row in front:\n")) ;
+    DEBUG6 (("fspos: "ID" flpos: "ID"\n", fspos, fnrows)) ;
+
+    if (fspos == fnrows)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* move Fs => Fd */
+       /* ------------------------------------------------------------------ */
+
+       DEBUG6 (("row case 1\n")) ;
+
+       /* row of the contribution block: */
+       {
+           Int j ;
+           Entry *Fd, *Fs ;
+           Fd = Fublock + fnpiv * fnc_curr ;
+           Fs = Fcblock + fspos ;
+#pragma ivdep
+           for (j = 0 ; j < fncols ; j++)
+           {
+               Fd [j] = Fs [j * fnr_curr] ;
+           }
+       }
+
+       /* row of the L2 block: */
+       if (Work->pivrow_in_front)
+       {
+           Int j ;
+           Entry *Fd, *Fs ;
+           Fd = Flublock + fnpiv ;
+           Fs = Flblock  + fspos ;
+#pragma ivdep
+           for (j = 0 ; j <= fnpiv ; j++)
+           {
+               Fd [j * nb] = Fs [j * fnr_curr] ;
+           }
+       }
+       else
+       {
+           Int j ;
+           Entry *Fd, *Fs ;
+           Fd = Flublock + fnpiv ;
+           Fs = Flblock  + fspos ;
+#pragma ivdep
+           for (j = 0 ; j < fnpiv ; j++)
+           {
+               ASSERT (IS_ZERO (Fs [j * fnr_curr])) ;
+               CLEAR (Fd [j * nb]) ;
+           }
+           Fd [fnpiv * nb] = Fs [fnpiv * fnr_curr] ;
+       }
+    }
+    else
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* move Fs => Fd */
+       /* move Fe => Fs */
+       /* ------------------------------------------------------------------ */
+
+       DEBUG6 (("row case 2\n")) ;
+       /* this is the most common case, by far */
+
+       /* row of the contribution block: */
+       {
+           /* Fd: destination of pivot row on U block */
+           /* Fs: current position of pivot row in contribution block */
+           /* Fe: position of last row in contribution block */
+           Entry *Fd, *Fs, *Fe ;
+           Fd = Fublock + fnpiv * fnc_curr ;
+           Fs = Fcblock + fspos ;
+           Fe = Fcblock + fnrows ;
+           shift_pivot_row (Fd, Fs, Fe, fncols, fnr_curr) ;
+       }
+
+       /* row of the L2 block: */
+       if (Work->pivrow_in_front)
+       {
+           /* Fd: destination of pivot row in LU block */
+           /* Fs: current position of pivot row in L block */
+           /* Fe: last row in L block */
+           Int j ;
+           Entry *Fd, *Fs, *Fe ;
+           Fd = Flublock + fnpiv ;
+           Fs = Flblock  + fspos ;
+           Fe = Flblock  + fnrows ;
+#pragma ivdep
+           for (j = 0 ; j <= fnpiv ; j++)
+           {
+               Fd [j * nb]       = Fs [j * fnr_curr] ;
+               Fs [j * fnr_curr] = Fe [j * fnr_curr] ;
+           }
+       }
+       else
+       {
+           Int j ;
+           Entry *Fd, *Fs, *Fe ;
+           Fd = Flublock + fnpiv ;
+           Fs = Flblock  + fspos ;
+           Fe = Flblock  + fnrows ;
+#pragma ivdep
+           for (j = 0 ; j < fnpiv ; j++)
+           {
+               ASSERT (IS_ZERO (Fs [j * fnr_curr])) ;
+               CLEAR (Fd [j * nb]) ;
+               Fs [j * fnr_curr] = Fe [j * fnr_curr] ;
+           }
+           Fd [fnpiv * nb]       = Fs [fnpiv * fnr_curr] ;
+           Fs [fnpiv * fnr_curr] = Fe [fnpiv * fnr_curr] ;
+       }
+
+       /* move row Fe to Fs in the Frows pattern */
+       row2 = Frows [fnrows] ;
+       Frows [fspos] = row2 ;
+       Frpos [row2] = fspos ;
+
+    }
+    /* pivot row is no longer in the frontal matrix */
+    Frpos [pivrow] = EMPTY ;
+
+#ifndef NDEBUG
+    DEBUG2 (("\nFrontal matrix after row swap, including all space:\n"
+               "fnr_curr "ID" fnc_curr "ID" nb    "ID"\n"
+               "fnrows   "ID" fncols   "ID" fnpiv "ID"\n",
+               Work->fnr_curr, Work->fnc_curr, Work->nb,
+               Work->fnrows, Work->fncols, Work->fnpiv)) ;
+    DEBUG2 (("\nJust the active part:\n")) ;
+    DEBUG7 (("C  block: ")) ;
+    UMF_dump_dense (Fcblock,  fnr_curr, fnrows, fncols) ;
+    DEBUG7 (("L  block: ")) ;
+    UMF_dump_dense (Flblock,  fnr_curr, fnrows, fnpiv+1);
+    DEBUG7 (("U' block: ")) ;
+    UMF_dump_dense (Fublock,  fnc_curr, fncols, fnpiv+1) ;
+    DEBUG7 (("LU block: ")) ;
+    UMF_dump_dense (Flublock, nb, fnpiv+1, fnpiv+1) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* Frpos [row] >= 0 for each row in pivot column pattern.   */
+    /* offset into pattern is given by:                                */
+    /* Frpos [row] == offset - 1                               */
+    /* Frpos [pivrow] is EMPTY */
+
+    /* Fcpos [col] >= 0 for each col in pivot row pattern.     */
+    /* Fcpos [col] == (offset - 1) * fnr_curr                  */
+    /* Fcpos [pivcol] is EMPTY */
+
+    /* Fcols [0..fncols-1] is the pivot row pattern (excl pivot cols) */
+    /* Frows [0..fnrows-1] is the pivot col pattern (excl pivot rows) */
+
+    /* ====================================================================== */
+    /* === scale pivot column =============================================== */
+    /* ====================================================================== */
+
+    /* pivot column (except for pivot entry itself) */
+    Fcol = Flblock + fnpiv * fnr_curr ;
+    /* fnpiv-th pivot in frontal matrix located in Flublock (fnpiv, fnpiv) */
+    pivot_value = Flublock [fnpiv + fnpiv * nb] ;
+
+    /* this is the kth global pivot */
+    k = Work->npiv + fnpiv ;
+
+    DEBUG4 (("Pivot value: ")) ;
+    EDEBUG4 (pivot_value) ;
+    DEBUG4 (("\n")) ;
+
+    UMF_scale (fnrows, pivot_value, Fcol) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* deallocate the pivot row and pivot column tuples */
+    /* ---------------------------------------------------------------------- */
+
+    UMF_mem_free_tail_block (Numeric, Row_tuples [pivrow]) ;
+    UMF_mem_free_tail_block (Numeric, Col_tuples [pivcol]) ;
+
+    Row_tuples [pivrow] = 0 ;
+    Col_tuples [pivcol] = 0 ;
+
+    DEBUG5 (("number of pivots prior to this one: "ID"\n", k)) ;
+    ASSERT (NON_PIVOTAL_ROW (pivrow)) ;
+    ASSERT (NON_PIVOTAL_COL (pivcol)) ;
+
+    /* save row and column inverse permutation */
+    k1 = ONES_COMPLEMENT (k) ;
+    Rperm [pivrow] = k1 ;                      /* aliased with Row_degree */
+    Cperm [pivcol] = k1 ;                      /* aliased with Col_degree */
+
+    ASSERT (!NON_PIVOTAL_ROW (pivrow)) ;
+    ASSERT (!NON_PIVOTAL_COL (pivcol)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* Keep track of the pivot order.  This is the kth pivot row and column. */
+    /* ---------------------------------------------------------------------- */
+
+    /* keep track of pivot rows and columns in the LU, L, and U blocks */
+    ASSERT (fnpiv < MAXNB) ;
+    Work->Pivrow [fnpiv] = pivrow ;
+    Work->Pivcol [fnpiv] = pivcol ;
+
+    /* ====================================================================== */
+    /* === one step in the factorization is done ============================ */
+    /* ====================================================================== */
+
+    /* One more step is done, except for pending updates to the U and C blocks
+     * of this frontal matrix.  Those are saved up, and applied by
+     * UMF_blas3_update when enough pivots have accumulated.   Also, the
+     * LU factors for these pending pivots have not yet been stored. */
+
+    Work->fnpiv++ ;
+
+#ifndef NDEBUG
+    DEBUG7 (("Current frontal matrix: (after pivcol scale)\n")) ;
+    UMF_dump_current_front (Numeric, Work, TRUE) ;
+#endif
+
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_scale_column.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_scale_column.h
new file mode 100644 (file)
index 0000000..fe38363
--- /dev/null
@@ -0,0 +1,12 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_scale_column
+(
+    NumericType *Numeric,
+    WorkType *Work
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_set_stats.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_set_stats.c
new file mode 100644 (file)
index 0000000..63e51a7
--- /dev/null
@@ -0,0 +1,134 @@
+/* ========================================================================== */
+/* === UMF_set_stats ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Sets statistics in Info array.  Calculates everything in double precision,
+    rather than Int or size_t, so that usage estimates can be computed even if
+    the problem is so large that it would cause integer overflow.
+
+    This routine has many double relop's, but the NaN case is ignored.
+*/
+
+#include "umf_internal.h"
+#include "umf_symbolic_usage.h"
+
+GLOBAL void UMF_set_stats
+(
+    double Info [ ],
+    SymbolicType *Symbolic,
+    double max_usage,          /* peak size of Numeric->Memory, in Units */
+    double num_mem_size,       /* final size of Numeric->Memory, in Units */
+    double flops,              /* "true flops" */
+    double lnz,                        /* nz in L */
+    double unz,                        /* nz in U */
+    double maxfrsize,          /* largest front size */
+    double ulen,               /* size of Numeric->Upattern */
+    double npiv,               /* number of pivots found */
+    double maxnrows,           /* largest #rows in front */
+    double maxncols,           /* largest #cols in front */
+    Int scale,                 /* true if scaling the rows of A */
+    Int prefer_diagonal,       /* true if diagonal pivoting (only square A) */
+    Int what                   /* ESTIMATE or ACTUAL */
+)
+{
+
+    double sym_size, work_usage, nn, n_row, n_col, n_inner, num_On_size1,
+       num_On_size2, num_usage, sym_maxncols, sym_maxnrows, elen, n1 ;
+
+    n_col = Symbolic->n_col ;
+    n_row = Symbolic->n_row ;
+    n1 = Symbolic->n1 ;
+    nn = MAX (n_row, n_col) ;
+    n_inner = MIN (n_row, n_col) ;
+    sym_maxncols = MIN (Symbolic->maxncols + Symbolic->nb, n_col) ;
+    sym_maxnrows = MIN (Symbolic->maxnrows + Symbolic->nb, n_row) ;
+    elen = (n_col - n1) + (n_row - n1) + MIN (n_col - n1, n_row - n1) + 1 ;
+
+    /* final Symbolic object size */
+    sym_size = UMF_symbolic_usage (Symbolic->n_row, Symbolic->n_col,
+       Symbolic->nchains, Symbolic->nfr, Symbolic->esize, prefer_diagonal) ;
+
+    /* size of O(n) part of Numeric object during factorization, */
+    /* except Numeric->Memory and Numeric->Upattern */
+    num_On_size1 =
+       DUNITS (NumericType, 1)         /* Numeric structure */
+       + DUNITS (Entry, n_inner+1)     /* D */
+       + 4 * DUNITS (Int, n_row+1)     /* Rperm, Lpos, Uilen, Uip */
+       + 4 * DUNITS (Int, n_col+1)     /* Cperm, Upos, Lilen, Lip */
+       + (scale ? DUNITS (Entry, n_row) : 0) ;   /* Rs, row scale factors */
+
+    /* size of O(n) part of Numeric object after factorization, */
+    /* except Numeric->Memory and Numeric->Upattern */
+    num_On_size2 =
+       DUNITS (NumericType, 1)         /* Numeric structure */
+       + DUNITS (Entry, n_inner+1)     /* D */
+       + DUNITS (Int, n_row+1)         /* Rperm */
+       + DUNITS (Int, n_col+1)         /* Cperm */
+       + 6 * DUNITS (Int, npiv+1)      /* Lpos, Uilen, Uip, Upos, Lilen, Lip */
+       + (scale ? DUNITS (Entry, n_row) : 0) ;     /* Rs, row scale factors */
+
+    DEBUG1 (("num O(n) size2: %g\n", num_On_size2)) ;
+
+    /* peak size of Numeric->Memory, including LU factors, current frontal
+     * matrix, elements, and tuple lists.  */
+    Info [UMFPACK_VARIABLE_PEAK + what] = max_usage ;
+
+    /* final size of Numeric->Memory (LU factors only) */
+    Info [UMFPACK_VARIABLE_FINAL + what] = num_mem_size ;
+
+    /* final size of Numeric object, including Numeric->Memory and ->Upattern */
+    Info [UMFPACK_NUMERIC_SIZE + what] =
+       num_On_size2
+       + num_mem_size          /* final Numeric->Memory size */
+       + DUNITS (Int, ulen+1) ;/* Numeric->Upattern (from Work->Upattern) */
+
+    DEBUG1 (("num mem size: %g\n", num_mem_size)) ;
+    DEBUG1 (("ulen units %g\n", DUNITS (Int, ulen))) ;
+    DEBUG1 (("numeric size %g\n", Info [UMFPACK_NUMERIC_SIZE + what])) ;
+
+    /* largest front size (working array size, or actual size used) */
+    Info [UMFPACK_MAX_FRONT_SIZE + what] = maxfrsize ;
+    Info [UMFPACK_MAX_FRONT_NROWS + what] = maxnrows ;
+    Info [UMFPACK_MAX_FRONT_NCOLS + what] = maxncols ;
+    DEBUGm4 (("maxnrows %g maxncols %g\n", maxnrows, maxncols)) ;
+    DEBUGm4 (("maxfrsize %g\n", maxfrsize)) ;
+
+    /* UMF_kernel usage, from work_alloc routine in umf_kernel.c */
+    work_usage =
+       /* Work-> arrays, except for current frontal matrix which is allocated
+        * inside Numeric->Memory. */
+       2 * DUNITS (Entry, sym_maxnrows + 1)    /* Wx, Wy */
+       + 2 * DUNITS (Int, n_row+1)             /* Frpos, Lpattern */
+       + 2 * DUNITS (Int, n_col+1)             /* Fcpos, Upattern */
+       + DUNITS (Int, nn + 1)                  /* Wp */
+       + DUNITS (Int, MAX (n_col, sym_maxnrows) + 1)   /* Wrp */
+       + 2 * DUNITS (Int, sym_maxnrows + 1)    /* Frows, Wm */
+       + 3 * DUNITS (Int, sym_maxncols + 1)    /* Fcols, Wio, Woi */
+       + DUNITS (Int, MAX (sym_maxnrows, sym_maxncols) + 1)    /* Woo */
+       + DUNITS (Int, elen)                    /* E */
+       + DUNITS (Int, Symbolic->nfr + 1)       /* Front_new1strow */
+       + ((n_row == n_col) ? (2 * DUNITS (Int, nn)) : 0) ;  /* Diag map,imap */
+
+    /* Peak memory for just UMFPACK_numeric. */
+    num_usage =
+       sym_size        /* size of Symbolic object */
+       + num_On_size1  /* O(n) part of Numeric object (excl. Upattern) */
+       + work_usage    /* Work-> arrays (including Upattern) */
+       + max_usage ;   /* peak size of Numeric->Memory */
+
+    /* peak memory usage for both UMFPACK_*symbolic and UMFPACK_numeric. */
+    Info [UMFPACK_PEAK_MEMORY + what] =
+       MAX (Symbolic->peak_sym_usage, num_usage) ;
+
+    Info [UMFPACK_FLOPS + what] = flops ;
+    Info [UMFPACK_LNZ + what] = lnz ;
+    Info [UMFPACK_UNZ + what] = unz ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_set_stats.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_set_stats.h
new file mode 100644 (file)
index 0000000..5b0a6c4
--- /dev/null
@@ -0,0 +1,25 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_set_stats
+(
+    double Info [ ],
+    SymbolicType *Symbolic,
+    double max_usage,
+    double num_mem_size,
+    double flops,
+    double lnz,
+    double unz,
+    double maxfrsize,
+    double ulen,
+    double npiv,
+    double maxnrows,
+    double maxncols,
+    Int scale,
+    Int prefer_diagonal,
+    Int what
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_singletons.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_singletons.c
new file mode 100644 (file)
index 0000000..841edee
--- /dev/null
@@ -0,0 +1,891 @@
+/* ========================================================================== */
+/* === UMF_singletons ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* Find and order the row and column singletons of a matrix A.  If there are
+ * row and column singletons, the output is a row and column permutation such
+ * that the matrix is in the following form:
+ *
+ *     x x x x x x x x x
+ *     0 x x x x x x x x
+ *     0 0 x x x x x x x
+ *     0 0 0 x 0 0 0 0 0
+ *     0 0 0 x x 0 0 0 0
+ *     0 0 0 x x s s s s
+ *     0 0 0 x x s s s s
+ *     0 0 0 x x s s s s
+ *     0 0 0 x x s s s s
+ *
+ * The above example has 3 column singletons (the first three columns and
+ * their corresponding pivot rows) and 2 row singletons.  The singletons are
+ * ordered first, because they have zero Markowitz cost.  The LU factorization
+ * for these first five rows and columns is free - there is no work to do
+ * (except to scale the pivot columns for the 2 row singletons), and no
+ * fill-in occurs.  * The remaining * submatrix (4-by-4 in the above example)
+ * has no rows or columns with degree one.  It may have empty rows or columns.
+ *
+ * This algorithm does not perform a full permutation to block triangular
+ * form.  If there are one or more singletons, then the matrix can be
+ * permuted to block triangular form, but UMFPACK does not perform the full
+ * BTF permutation (see also "dmperm" in MATLAB).
+ */
+
+#include "umf_internal.h"
+
+#ifndef NDEBUG
+
+/* ========================================================================== */
+/* === debug routines ======================================================= */
+/* ========================================================================== */
+
+/* Dump the singleton queue */
+
+PRIVATE void dump_singletons
+(
+    Int head,          /* head of the queue */
+    Int tail,          /* tail of the queue */
+    Int Next [ ],      /* Next [i] is the next object after i */
+    char *name,                /* "row" or "col" */
+    Int Deg [ ],       /* Deg [i] is the degree of object i */
+    Int n              /* objects are in the range 0 to n-1 */
+)
+{
+    Int i, next, cnt ;
+    DEBUG6 (("%s Singleton list: head "ID" tail "ID"\n", name, head, tail)) ;
+    i = head ;
+    ASSERT (head >= EMPTY && head < n) ;
+    ASSERT (tail >= EMPTY && tail < n) ;
+    cnt = 0 ;
+    while (i != EMPTY)
+    {
+       DEBUG7 ((" "ID": "ID" deg: "ID"\n", cnt, i, Deg [i])) ;
+       ASSERT (i >= 0 && i < n) ;
+       next = Next [i] ;
+       if (i == tail) ASSERT (next == EMPTY) ;
+       i = next ;
+       cnt++ ;
+       ASSERT (cnt <= n) ;
+    }
+}
+
+PRIVATE void dump_mat
+(
+    char *xname,
+    char *yname,
+    Int nx,
+    Int ny,
+    const Int Xp [ ],
+    const Int Xi [ ],
+    Int Xdeg [ ],
+    Int Ydeg [ ]
+)
+{
+    Int x, y, p, p1, p2, xdeg, do_xdeg, ydeg ;
+    DEBUG6 (("\n ==== Dump %s mat:\n", xname)) ;
+    for (x = 0 ; x < nx ; x++)
+    {
+       p1 = Xp [x] ;
+       p2 = Xp [x+1] ;
+       xdeg = Xdeg [x] ;
+       DEBUG6 (("Dump %s "ID" p1 "ID" p2 "ID" deg "ID"\n",
+           xname, x, p1, p2, xdeg)) ;
+       do_xdeg = (xdeg >= 0) ;
+       for (p = p1 ; p < p2 ; p++)
+       {
+           y = Xi [p] ;
+           DEBUG7 (("    %s "ID" deg: ", yname, y)) ;
+           ASSERT (y >= 0 && y < ny) ;
+           ydeg = Ydeg [y] ;
+           DEBUG7 ((ID"\n", ydeg)) ;
+           if (do_xdeg && ydeg >= 0)
+           {
+               xdeg-- ;
+           }
+       }
+       ASSERT (IMPLIES (do_xdeg, xdeg == 0)) ;
+    }
+}
+#endif
+
+/* ========================================================================== */
+/* === create_row_form ====================================================== */
+/* ========================================================================== */
+
+/* Create the row-form R of the column-form input matrix A.  This could be done
+ * by UMF_transpose, except that Rdeg has already been computed.
+ */
+
+PRIVATE void create_row_form
+(
+    /* input, not modified: */
+    Int n_row,             /* A is n_row-by-n_col, nz = Ap [n_col] */
+    Int n_col,
+    const Int Ap [ ],      /* Ap [0..n_col]: column pointers for A */
+    const Int Ai [ ],      /* Ai [0..nz-1]:  row indices for A */
+    Int Rdeg [ ],          /* Rdeg [0..n_row-1]: row degrees */
+
+    /* output, not defined on input: */
+    Int Rp [ ],                    /* Rp [0..n_row]: row pointers for R */
+    Int Ri [ ],                    /* Ri [0..nz-1]:  column indices for R */
+
+    /* workspace, not defined on input or output */
+    Int W [ ]              /* size n_row */
+)
+{
+    Int row, col, p, p2 ;
+
+    /* create the row pointers */
+    Rp [0] = 0 ;
+    W [0] = 0 ;
+    for (row = 0 ; row < n_row ; row++)
+    {
+       Rp [row+1] = Rp [row] + Rdeg [row] ;
+       W [row] = Rp [row] ;
+    }
+
+    /* create the indices for the row-form */
+    for (col = 0 ; col < n_col ; col++)
+    {
+       p2 = Ap [col+1] ;
+       for (p = Ap [col] ; p < p2 ; p++)
+       {
+           Ri [W [Ai [p]]++] = col ;
+       }
+    }
+}
+
+/* ========================================================================== */
+/* === order_singletons ===================================================== */
+/* ========================================================================== */
+
+PRIVATE int order_singletons   /* return new number of singletons */
+(
+    Int k,         /* the number of singletons so far */
+    Int head,
+    Int tail,
+    Int Next [ ],
+    Int Xdeg [ ], Int Xperm [ ], const Int Xp [ ], const Int Xi [ ],
+    Int Ydeg [ ], Int Yperm [ ], const Int Yp [ ], const Int Yi [ ]
+#ifndef NDEBUG
+    , char *xname, char *yname, Int nx, Int ny
+#endif
+)
+{
+    Int xpivot, x, y, ypivot, p, p2, deg ;
+
+#ifndef NDEBUG
+    Int i, k1 = k ;
+    dump_singletons (head, tail, Next, xname, Xdeg, nx) ;
+    dump_mat (xname, yname, nx, ny, Xp, Xi, Xdeg, Ydeg) ;
+    dump_mat (yname, xname, ny, nx, Yp, Yi, Ydeg, Xdeg) ;
+#endif
+
+    while (head != EMPTY)
+    {
+       /* remove the singleton at the head of the queue */
+       xpivot = head ;
+       DEBUG1 (("------ Order %s singleton: "ID"\n", xname, xpivot)) ;
+       head = Next [xpivot] ;
+       if (head == EMPTY) tail = EMPTY ;
+
+#ifndef NDEBUG
+       if (k % 100 == 0) dump_singletons (head, tail, Next, xname, Xdeg, nx) ;
+#endif
+
+       ASSERT (Xdeg [xpivot] >= 0) ;
+       if (Xdeg [xpivot] != 1)
+       {
+           /* This row/column x is empty.  The matrix is singular.
+            * x will be ordered last in Xperm. */
+           DEBUG1 (("empty %s, after singletons removed\n", xname)) ;
+           continue ;
+       }
+
+       /* find the ypivot to match with this xpivot */
+#ifndef NDEBUG
+       /* there can only be one ypivot, since the degree of x is 1 */
+       deg = 0 ;
+       p2 = Xp [xpivot+1] ;
+       for (p = Xp [xpivot] ; p < p2 ; p++)
+       {
+           y = Xi [p] ;
+           DEBUG1 (("%s: "ID"\n", yname, y)) ;
+           if (Ydeg [y] >= 0)
+           {
+               /* this is a live index in this xpivot vector */
+               deg++ ;
+           }
+       }
+       ASSERT (deg == 1) ;
+#endif
+
+       ypivot = EMPTY ;
+       p2 = Xp [xpivot+1] ;
+       for (p = Xp [xpivot] ; p < p2 ; p++)
+       {
+           y = Xi [p] ;
+           DEBUG1 (("%s: "ID"\n", yname, y)) ;
+           if (Ydeg [y] >= 0)
+           {
+               /* this is a live index in this xpivot vector */
+               ypivot = y ;
+               break ;
+           }
+       }
+
+       DEBUG1 (("Pivot %s: "ID"\n", yname, ypivot)) ;
+       ASSERT (ypivot != EMPTY) ;
+       DEBUG1 (("deg "ID"\n", Ydeg [ypivot])) ;
+       ASSERT (Ydeg [ypivot] >= 0) ;
+
+       /* decrement the degrees after removing this singleton */
+       DEBUG1 (("p1 "ID"\n", Yp [ypivot])) ;
+       DEBUG1 (("p2 "ID"\n", Yp [ypivot+1])) ;
+       p2 = Yp [ypivot+1] ;
+       for (p = Yp [ypivot] ; p < p2 ; p++)
+       {
+           x = Yi [p] ;
+           DEBUG1 (("    %s: "ID" deg: "ID"\n", xname, x, Xdeg [x])) ;
+           if (Xdeg [x] < 0) continue ;
+           ASSERT (Xdeg [x] > 0) ;
+           if (x == xpivot) continue ;
+           deg = --(Xdeg [x]) ;
+           ASSERT (Xdeg [x] >= 0) ;
+           if (deg == 1)
+           {
+               /* this is a new singleton, put at the end of the queue */
+               Next [x] = EMPTY ;
+               if (head == EMPTY)
+               {
+                   head = x ;
+               }
+               else
+               {
+                   ASSERT (tail != EMPTY) ;
+                   Next [tail] = x ;
+               }
+               tail = x ;
+               DEBUG1 ((" New %s singleton:  "ID"\n", xname, x)) ;
+#ifndef NDEBUG
+               if (k % 100 == 0)
+               {
+                   dump_singletons (head, tail, Next, xname, Xdeg, nx) ;
+               }
+#endif
+           }
+       }
+
+       /* flag the xpivot and ypivot by FLIP'ing the degrees */
+       Xdeg [xpivot] = FLIP (1) ;
+       Ydeg [ypivot] = FLIP (Ydeg [ypivot]) ;
+
+       /* keep track of the pivot row and column */
+       Xperm [k] = xpivot ;
+       Yperm [k] = ypivot ;
+       k++ ;
+
+#ifndef NDEBUG
+       if (k % 1000 == 0)
+       {
+           dump_mat (xname, yname, nx, ny, Xp, Xi, Xdeg, Ydeg) ;
+           dump_mat (yname, xname, ny, nx, Yp, Yi, Ydeg, Xdeg) ;
+       }
+#endif
+    }
+
+#ifndef NDEBUG
+    DEBUGm4 (("%s singletons: k = "ID"\n", xname, k)) ;
+    for (i = k1 ; i < k ; i++)
+    {
+       DEBUG1 (("  %s: "ID" %s: "ID"\n", xname, Xperm [i], yname, Yperm [i])) ;
+    }
+    ASSERT (k > 0) ;
+#endif
+
+    return (k) ;
+}
+
+/* ========================================================================== */
+/* === find_any_singletons ================================================== */
+/* ========================================================================== */
+
+PRIVATE Int find_any_singletons            /* returns # of singletons found */
+(
+    /* input, not modified: */
+    Int n_row,
+    Int n_col,
+    const Int Ap [ ],      /* size n_col+1 */
+    const Int Ai [ ],      /* size nz = Ap [n_col] */
+
+    /* input, modified on output: */
+    Int Cdeg [ ],          /* size n_col */
+    Int Rdeg [ ],          /* size n_row */
+
+    /* output, not defined on input: */
+    Int Cperm [ ],         /* size n_col */
+    Int Rperm [ ],         /* size n_row */
+    Int *p_n1r,                    /* # of row singletons */
+    Int *p_n1c,                    /* # of col singletons */
+
+    /* workspace, not defined on input or output */
+    Int Rp [ ],                    /* size n_row+1 */
+    Int Ri [ ],                    /* size nz */
+    Int W [ ],             /* size n_row */
+    Int Next [ ]           /* size MAX (n_row, n_col) */
+)
+{
+    Int n1, col, row, row_form, head, tail, n1r, n1c ;
+
+    /* ---------------------------------------------------------------------- */
+    /* eliminate column singletons */
+    /* ---------------------------------------------------------------------- */
+
+    n1 = 0 ;
+    n1r = 0 ;
+    n1c = 0 ;
+    row_form = FALSE ;
+
+    head = EMPTY ;
+    tail = EMPTY ;
+    for (col = n_col-1 ; col >= 0 ; col--)
+    {
+       if (Cdeg [col] == 1)
+       {
+           /* put the column singleton in the queue */
+           if (head == EMPTY) tail = col ;
+           Next [col] = head ;
+           head = col ;
+           DEBUG1 (("Column singleton: "ID"\n", col)) ;
+       }
+    }
+
+    if (head != EMPTY)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* create the row-form of A */
+       /* ------------------------------------------------------------------ */
+
+       create_row_form (n_row, n_col, Ap, Ai, Rdeg, Rp, Ri, W) ;
+       row_form = TRUE ;
+
+       /* ------------------------------------------------------------------ */
+       /* find and order the column singletons */
+       /* ------------------------------------------------------------------ */
+
+       n1 = order_singletons (0, head, tail, Next,
+               Cdeg, Cperm, Ap, Ai,
+               Rdeg, Rperm, Rp, Ri
+#ifndef NDEBUG
+               , "col", "row", n_col, n_row
+#endif
+               ) ;
+       n1c = n1 ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* eliminate row singletons */
+    /* ---------------------------------------------------------------------- */
+
+    head = EMPTY ;
+    tail = EMPTY ;
+    for (row = n_row-1 ; row >= 0 ; row--)
+    {
+       if (Rdeg [row] == 1)
+       {
+           /* put the row singleton in the queue */
+           if (head == EMPTY) tail = row ;
+           Next [row] = head ;
+           head = row ;
+           DEBUG1 (("Row singleton: "ID"\n", row)) ;
+       }
+    }
+
+    if (head != EMPTY)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* create the row-form of A, if not already created */
+       /* ------------------------------------------------------------------ */
+
+       if (!row_form)
+       {
+           create_row_form (n_row, n_col, Ap, Ai, Rdeg, Rp, Ri, W) ;
+       }
+
+       /* ------------------------------------------------------------------ */
+       /* find and order the row singletons */
+       /* ------------------------------------------------------------------ */
+
+       n1 = order_singletons (n1, head, tail, Next,
+               Rdeg, Rperm, Rp, Ri,
+               Cdeg, Cperm, Ap, Ai
+#ifndef NDEBUG
+               , "row", "col", n_row, n_col
+#endif
+               ) ;
+       n1r = n1 - n1c ;
+    }
+
+    DEBUG0 (("n1 "ID"\n", n1)) ;
+    *p_n1r = n1r ;
+    *p_n1c = n1c ;
+    return (n1) ;
+}
+
+/* ========================================================================== */
+/* === find_user_singletons ================================================= */
+/* ========================================================================== */
+
+PRIVATE Int find_user_singletons       /* returns # singletons found */
+(
+    /* input, not modified: */
+    Int n_row,
+    Int n_col,
+    const Int Ap [ ],      /* size n_col+1 */
+    const Int Ai [ ],      /* size nz = Ap [n_col] */
+    const Int Quser [ ],    /* size n_col if present */
+
+    /* input, modified on output: */
+    Int Cdeg [ ],          /* size n_col */
+    Int Rdeg [ ],          /* size n_row */
+
+    /* output, not defined on input */
+    Int Cperm [ ],         /* size n_col */
+    Int Rperm [ ],         /* size n_row */
+    Int *p_n1r,                    /* # of row singletons */
+    Int *p_n1c,                    /* # of col singletons */
+
+    /* workspace, not defined on input or output */
+    Int Rp [ ],                    /* size n_row+1 */
+    Int Ri [ ],                    /* size nz */
+    Int W [ ]              /* size n_row */
+)
+{
+    Int n1, col, row, p, p2, pivcol, pivrow, found, k, n1r, n1c ;
+
+    n1 = 0 ;
+    n1r = 0 ;
+    n1c = 0 ;
+    *p_n1r = 0 ;
+    *p_n1c = 0 ;
+
+    /* find singletons in the user column permutation, Quser */
+    pivcol = Quser [0] ;
+    found = (Cdeg [pivcol] == 1) ;
+    DEBUG0 (("Is first col: "ID" a col singleton?: "ID"\n", pivcol, found)) ;
+    if (!found)
+    {
+       /* the first column is not a column singleton, check for a row
+        * singleton in the first column. */
+       for (p = Ap [pivcol] ; p < Ap [pivcol+1] ; p++)
+       {
+           if (Rdeg [Ai [p]] == 1)
+           {
+               DEBUG0 (("Row singleton in first col: "ID" row: "ID"\n",
+                   pivcol, Ai [p])) ;
+               found = TRUE ;
+               break ;
+           }
+       }
+    }
+
+    if (!found)
+    {
+       /* no singletons in the leading part of A (:,Quser) */
+       return (0) ;
+    }
+
+    /* there is at least one row or column singleton.  Look for more. */
+    create_row_form (n_row, n_col, Ap, Ai, Rdeg, Rp, Ri, W) ;
+
+    n1 = 0 ;
+
+    for (k = 0 ; k < n_col ; k++)
+    {
+       pivcol = Quser [k] ;
+       pivrow = EMPTY ;
+
+       /* ------------------------------------------------------------------ */
+       /* check if col is a column singleton, or contains a row singleton */
+       /* ------------------------------------------------------------------ */
+
+       found = (Cdeg [pivcol] == 1) ;
+
+       if (found)
+       {
+
+           /* -------------------------------------------------------------- */
+           /* pivcol is a column singleton */
+           /* -------------------------------------------------------------- */
+
+           DEBUG0 (("Found a col singleton: k "ID" pivcol "ID"\n", k, pivcol));
+
+           /* find the pivrow to match with this pivcol */
+#ifndef NDEBUG
+           /* there can only be one pivrow, since the degree of pivcol is 1 */
+           {
+               Int deg = 0 ;
+               p2 = Ap [pivcol+1] ;
+               for (p = Ap [pivcol] ; p < p2 ; p++)
+               {
+                   row = Ai [p] ;
+                   DEBUG1 (("row: "ID"\n", row)) ;
+                   if (Rdeg [row] >= 0)
+                   {
+                       /* this is a live index in this column vector */
+                       deg++ ;
+                   }
+               }
+               ASSERT (deg == 1) ;
+           }
+#endif
+
+           p2 = Ap [pivcol+1] ;
+           for (p = Ap [pivcol] ; p < p2 ; p++)
+           {
+               row = Ai [p] ;
+               DEBUG1 (("row: "ID"\n", row)) ;
+               if (Rdeg [row] >= 0)
+               {
+                   /* this is a live index in this pivcol vector */
+                   pivrow = row ;
+                   break ;
+               }
+           }
+
+           DEBUG1 (("Pivot row: "ID"\n", pivrow)) ;
+           ASSERT (pivrow != EMPTY) ;
+           DEBUG1 (("deg "ID"\n", Rdeg [pivrow])) ;
+           ASSERT (Rdeg [pivrow] >= 0) ;
+
+           /* decrement the degrees after removing this col singleton */
+           DEBUG1 (("p1 "ID"\n", Rp [pivrow])) ;
+           DEBUG1 (("p2 "ID"\n", Rp [pivrow+1])) ;
+           p2 = Rp [pivrow+1] ;
+           for (p = Rp [pivrow] ; p < p2 ; p++)
+           {
+               col = Ri [p] ;
+               DEBUG1 (("    col: "ID" deg: "ID"\n", col, Cdeg [col])) ;
+               if (Cdeg [col] < 0) continue ;
+               ASSERT (Cdeg [col] > 0) ;
+               Cdeg [col]-- ;
+               ASSERT (Cdeg [col] >= 0) ;
+           }
+
+           /* flag the pivcol and pivrow by FLIP'ing the degrees */
+           Cdeg [pivcol] = FLIP (1) ;
+           Rdeg [pivrow] = FLIP (Rdeg [pivrow]) ;
+           n1c++ ;
+
+       }
+       else
+       {
+
+           /* -------------------------------------------------------------- */
+           /* pivcol may contain a row singleton */
+           /* -------------------------------------------------------------- */
+
+           p2 = Ap [pivcol+1] ;
+           for (p = Ap [pivcol] ; p < p2 ; p++)
+           {
+               pivrow = Ai [p] ;
+               if (Rdeg [pivrow] == 1)
+               {
+                   DEBUG0 (("Row singleton in pivcol: "ID" row: "ID"\n",
+                       pivcol, pivrow)) ;
+                   found = TRUE ;
+                   break ;
+               }
+           }
+
+           if (!found)
+           {
+               DEBUG0 (("End of user singletons\n")) ;
+               break ;
+           }
+
+#ifndef NDEBUG
+           /* there can only be one pivrow, since the degree of pivcol is 1 */
+           {
+               Int deg = 0 ;
+               p2 = Rp [pivrow+1] ;
+               for (p = Rp [pivrow] ; p < p2 ; p++)
+               {
+                   col = Ri [p] ;
+                   DEBUG1 (("col: "ID" cdeg::: "ID"\n", col, Cdeg [col])) ;
+                   if (Cdeg [col] >= 0)
+                   {
+                       /* this is a live index in this column vector */
+                       ASSERT (col == pivcol) ;
+                       deg++ ;
+                   }
+               }
+               ASSERT (deg == 1) ;
+           }
+#endif
+
+           DEBUG1 (("Pivot row: "ID"\n", pivrow)) ;
+           DEBUG1 (("pivcol deg "ID"\n", Cdeg [pivcol])) ;
+           ASSERT (Cdeg [pivcol] > 1) ;
+
+           /* decrement the degrees after removing this row singleton */
+           DEBUG1 (("p1 "ID"\n", Ap [pivcol])) ;
+           DEBUG1 (("p2 "ID"\n", Ap [pivcol+1])) ;
+           p2 = Ap [pivcol+1] ;
+           for (p = Ap [pivcol] ; p < p2 ; p++)
+           {
+               row = Ai [p] ;
+               DEBUG1 (("    row: "ID" deg: "ID"\n", row, Rdeg [row])) ;
+               if (Rdeg [row] < 0) continue ;
+               ASSERT (Rdeg [row] > 0) ;
+               Rdeg [row]-- ;
+               ASSERT (Rdeg [row] >= 0) ;
+           }
+
+           /* flag the pivcol and pivrow by FLIP'ing the degrees */
+           Cdeg [pivcol] = FLIP (Cdeg [pivcol]) ;
+           Rdeg [pivrow] = FLIP (1) ;
+           n1r++ ;
+       }
+
+       /* keep track of the pivot row and column */
+       Cperm [k] = pivcol ;
+       Rperm [k] = pivrow ;
+       n1++ ;
+
+#ifndef NDEBUG
+       dump_mat ("col", "row", n_col, n_row, Ap, Ai, Cdeg, Rdeg) ;
+       dump_mat ("row", "col", n_row, n_col, Rp, Ri, Rdeg, Cdeg) ;
+#endif
+
+    }
+
+    DEBUGm4 (("User singletons found: "ID"\n", n1)) ;
+    ASSERT (n1 > 0) ;
+
+    *p_n1r = n1r ;
+    *p_n1c = n1c ;
+    return (n1) ;
+}
+
+/* ========================================================================== */
+/* === finish_permutation =================================================== */
+/* ========================================================================== */
+
+/* Complete the permutation for the pruned submatrix.  The singletons are
+ * already ordered, but remove their flags.  Place rows/columns that are empty
+ * in the pruned submatrix at the end of the output permutation.  This can only
+ * occur if the matrix is singular.
+ */
+
+PRIVATE Int finish_permutation
+(
+    Int n1,
+    Int nx,
+    Int Xdeg [ ],
+    const Int Xuser [ ],
+    Int Xperm [ ],
+    Int *p_max_deg
+)
+{
+    Int nempty, x, deg, s, max_deg, k ;
+    nempty = 0 ;
+    s = n1 ;
+    max_deg = 0 ;
+    DEBUG0 (("n1 "ID" nempty "ID"\n", n1, nempty)) ;
+    for (k = 0 ; k < nx ; k++)
+    {
+       x = (Xuser != (Int *) NULL) ? Xuser [k] : k ;
+       DEBUG0 (("finish perm k "ID" x "ID" nx "ID"\n", k, x, nx)) ;
+       deg = Xdeg [x] ;
+       if (deg == 0)
+       {
+           /* this row/col is empty in the pruned submatrix */
+           ASSERT (s < nx - nempty) ;
+           nempty++ ;
+           Xperm [nx - nempty] = x ;
+       }
+       else if (deg > 0)
+       {
+           /* this row/col is nonempty in the pruned submatrix */
+           ASSERT (s < nx - nempty) ;
+           Xperm [s++] = x ;
+           max_deg = MAX (max_deg, deg) ;
+       }
+       else
+       {
+           /* This is a singleton row/column - it is already ordered.
+            * Just clear the flag. */
+           Xdeg [x] = FLIP (deg) ;
+       }
+    }
+    ASSERT (s == nx - nempty) ;
+    *p_max_deg = max_deg ;
+    return (nempty) ;
+}
+
+/* ========================================================================== */
+/* === UMF_singletons ======================================================= */
+/* ========================================================================== */
+
+GLOBAL Int UMF_singletons
+(
+
+    /* input, not modified: */
+    Int n_row,
+    Int n_col,
+    const Int Ap [ ],      /* size n_col+1 */
+    const Int Ai [ ],      /* size nz = Ap [n_col] */
+    const Int Quser [ ],    /* size n_col if present */
+
+    /* output, not defined on input: */
+    Int Cdeg [ ],      /* size n_col */
+    Int Cperm [ ],     /* size n_col */
+    Int Rdeg [ ],      /* size n_row */
+    Int Rperm [ ],     /* size n_row */
+    Int InvRperm [ ],  /* size n_row, the inverse of Rperm */
+    Int *p_n1,         /* # of col and row singletons */
+    Int *p_n1c,                /* # of col singletons */
+    Int *p_n1r,                /* # of row singletons */
+    Int *p_nempty_col, /* # of empty columns in pruned submatrix */
+    Int *p_nempty_row, /* # of empty columns in pruned submatrix */
+    Int *p_is_sym,     /* TRUE if pruned submatrix is square and has been
+                        * symmetrically permuted by Cperm and Rperm */
+    Int *p_max_rdeg,   /* maximum Rdeg in pruned submatrix */
+
+    /* workspace, not defined on input or output */
+    Int Rp [ ],                /* size n_row+1 */
+    Int Ri [ ],                /* size nz */
+    Int W [ ],         /* size n_row */
+    Int Next [ ]       /* size MAX (n_row, n_col) */
+)
+{
+    Int n1, s, col, row, p, p1, p2, cdeg, last_row, is_sym, k,
+       nempty_row, nempty_col, max_cdeg, max_rdeg, n1c, n1r ;
+
+    /* ---------------------------------------------------------------------- */
+    /* initializations */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    UMF_dump_start ( ) ;
+    DEBUGm4 (("Starting umf_singletons\n")) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* scan the columns, check for errors and count row degrees */
+    /* ---------------------------------------------------------------------- */
+
+    if (Ap [0] != 0 || Ap [n_col] < 0)
+    {
+       return (UMFPACK_ERROR_invalid_matrix) ;
+    }
+    for (row = 0 ; row < n_row ; row++)
+    {
+       Rdeg [row] = 0 ;
+    }
+    for (col = 0 ; col < n_col ; col++)
+    {
+       p1 = Ap [col] ;
+       p2 = Ap [col+1] ;
+       cdeg = p2 - p1 ;
+       if (cdeg < 0)
+       {
+           return (UMFPACK_ERROR_invalid_matrix) ;
+       }
+       last_row = EMPTY ;
+       for (p = p1 ; p < p2 ; p++)
+       {
+           row = Ai [p] ;
+           if (row <= last_row || row >= n_row)
+           {
+               return (UMFPACK_ERROR_invalid_matrix) ;
+           }
+           Rdeg [row]++ ;
+           last_row = row ;
+       }
+       Cdeg [col] = cdeg ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* find singletons */
+    /* ---------------------------------------------------------------------- */
+
+    if (Quser != (Int *) NULL)
+    {
+       /* look for singletons, but respect the user's input permutation */
+       n1 = find_user_singletons (n_row, n_col, Ap, Ai, Quser,
+               Cdeg, Rdeg, Cperm, Rperm, &n1r, &n1c, Rp, Ri, W) ;
+    }
+    else
+    {
+       /* look for singletons anywhere */
+       n1 = find_any_singletons (n_row, n_col, Ap, Ai,
+               Cdeg, Rdeg, Cperm, Rperm, &n1r, &n1c, Rp, Ri, W, Next) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* eliminate empty columns and complete the column permutation */
+    /* ---------------------------------------------------------------------- */
+
+    nempty_col = finish_permutation (n1, n_col, Cdeg, Quser, Cperm, &max_cdeg) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* eliminate empty rows and complete the row permutation */
+    /* ---------------------------------------------------------------------- */
+
+    nempty_row = finish_permutation (n1, n_row, Rdeg, (Int *) NULL, Rperm,
+       &max_rdeg) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the inverse of Rperm */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = 0 ; k < n_row ; k++)
+    {
+       ASSERT (Rperm [k] >= 0 && Rperm [k] < n_row) ;
+       InvRperm [Rperm [k]] = k ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* see if pruned submatrix is square and has been symmetrically permuted */
+    /* ---------------------------------------------------------------------- */
+
+    if (n_row == n_col && nempty_row == nempty_col)
+    {
+       /* is_sym is true if the submatrix is square, and
+        * Rperm [n1..n_row-nempty_row-1] = Cperm [n1..n_col-nempty_col-1] */
+       is_sym = TRUE ;
+       for (s = n1 ; s < n_col - nempty_col ; s++)
+       {
+           if (Cperm [s] != Rperm [s])
+           {
+               is_sym = FALSE ;
+               break ;
+           }
+       }
+    }
+    else
+    {
+       is_sym = FALSE ;
+    }
+    DEBUGm4 (("Submatrix square and symmetrically permuted? "ID"\n", is_sym)) ;
+    DEBUGm4 (("singletons "ID" row "ID" col "ID"\n", n1, n1r, n1c)) ;
+    DEBUGm4 (("Empty cols "ID" rows "ID"\n", nempty_col, nempty_row)) ;
+    *p_n1 = n1 ;
+    *p_n1r = n1r ;
+    *p_n1c = n1c ;
+    *p_is_sym = is_sym ;
+    *p_nempty_col = nempty_col ;
+    *p_nempty_row = nempty_row ;
+    *p_max_rdeg = max_rdeg ;
+    return (UMFPACK_OK) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_singletons.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_singletons.h
new file mode 100644 (file)
index 0000000..460defa
--- /dev/null
@@ -0,0 +1,31 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_singletons
+(
+    Int n_row,
+    Int n_col,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const Int Quser [ ],
+    Int Cdeg [ ],
+    Int Cperm [ ],
+    Int Rdeg [ ],
+    Int Rperm [ ],
+    Int InvRperm [ ],
+    Int *n1,
+    Int *n1c,
+    Int *n1r,
+    Int *nempty_col,
+    Int *nempty_row,
+    Int *is_sym,
+    Int *max_rdeg,
+    Int Rp [ ],
+    Int Ri [ ],
+    Int W [ ],
+    Int Next [ ]
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_solve.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_solve.c
new file mode 100644 (file)
index 0000000..8450c40
--- /dev/null
@@ -0,0 +1,1372 @@
+/* ========================================================================== */
+/* === UMF_solve ============================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Not user-callable.  Solves a linear system using the numerical factorization
+    computed by UMFPACK_numeric.  No workspace is dynamically allocated.  Counts
+    flops, but excludes floating-point comparisons (thus real abs (...) are
+    zero flops, but complex abs (...) takes 6 flops).
+
+    Returns UMFPACK_OK if successful, UMFPACK_ERROR_argument_missing if
+    required arguments are missing, UMFPACK_ERROR_invalid_system if the sys
+    string is not valid or if the matrix A is not square.
+
+    Uses the sparse backward error method of Arioli, Demmel, and Duff
+    (Solving sparse linear systems with sparse backward error, SIAM J. Matrix
+    Analysis and Applic., vol 10, pp. 165-190).
+*/
+
+#include "umf_internal.h"
+#include "umf_lsolve.h"
+#include "umf_usolve.h"
+#include "umf_ltsolve.h"
+#include "umf_utsolve.h"
+#include "umf_report_vector.h"
+
+PRIVATE Int do_step
+(
+    double omega [3],
+    Int step,
+    const double B2 [ ],
+    Entry X [ ],
+    const Entry W [ ],
+    const double Y [ ],
+    const double Z2 [ ],
+    Entry S [ ],
+    Int n,
+    double Info [UMFPACK_INFO]
+) ;
+
+/* ========================================================================== */
+/* === UMF_solve ============================================================ */
+/* ========================================================================== */
+
+GLOBAL Int UMF_solve
+(
+    Int sys,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const double Ax [ ],
+    double Xx [ ],
+    const double Bx [ ],
+#ifdef COMPLEX
+    const double Az [ ],
+    double Xz [ ],
+    const double Bz [ ],
+#endif
+    NumericType *Numeric,
+    Int irstep,
+    double Info [UMFPACK_INFO],
+    Int Pattern [ ],           /* size n */
+    double SolveWork [ ]       /* if irstep>0 real:  size 5*n.  complex:10*n */
+                               /* otherwise   real:  size   n.  complex: 4*n */
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int *Rperm, *Cperm, i, n, p, step, j, nz, status, p2, do_scale ;
+    Entry axx, wi, xj, zi, xi, aij, *W, *Z, *S, *X, bi ;
+    double omega [3], d, *Z2, *Y, z2i, yi, *B2, *Rs, flops ;
+
+#ifndef NRECIPROCAL
+    Int do_recip = Numeric->do_recip ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* initializations */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    UMF_dump_lu (Numeric) ;
+    ASSERT (Numeric && Xx && Bx && Pattern && SolveWork && Info) ;
+#ifdef COMPLEX
+    ASSERT (Xz && Bz) ;
+#endif
+#endif
+
+    nz = 0 ;
+    omega [0] = 0. ;
+    omega [1] = 0. ;
+    omega [2] = 0. ;
+    Rperm = Numeric->Rperm ;
+    Cperm = Numeric->Cperm ;
+    Rs = Numeric->Rs ;         /* row scale factors */
+    do_scale = (Rs != (double *) NULL) ;
+    flops = 0 ;
+    Info [UMFPACK_SOLVE_FLOPS] = 0 ;
+    Info [UMFPACK_IR_TAKEN] = 0 ;
+    Info [UMFPACK_IR_ATTEMPTED] = 0 ;
+
+    /* UMFPACK_solve does not call this routine if A is rectangular */
+    ASSERT (Numeric->n_row == Numeric->n_col) ;
+    n = Numeric->n_row ;
+    if (Numeric->nnzpiv < n
+       || SCALAR_IS_ZERO (Numeric->rcond) || SCALAR_IS_NAN (Numeric->rcond))
+    {
+       /* Note that systems involving just L return UMFPACK_OK, even if */
+       /* A is singular (L is always has a unit diagonal). */
+       DEBUGm4 (("Note, matrix is singular in umf_solve\n")) ;
+       status = UMFPACK_WARNING_singular_matrix ;
+       irstep = 0 ;
+    }
+    else
+    {
+       status = UMFPACK_OK ;
+    }
+    irstep = MAX (0, irstep) ;                 /* make sure irstep is >= 0 */
+
+    W = (Entry *) SolveWork ;                  /* Entry W [0..n-1] */
+
+    Z = (Entry *) NULL ;       /* unused if no iterative refinement */
+    S = (Entry *) NULL ;
+    Y = (double *) NULL ;
+    Z2 = (double *) NULL ;
+    B2 = (double *) NULL ;
+
+#ifdef COMPLEX
+    X = (Entry *) (SolveWork + 2*n) ;          /* Entry X [0..n-1] */
+    if (irstep > 0)
+    {
+       if (!Ap || !Ai || !Ax || !Az)
+       {
+           return (UMFPACK_ERROR_argument_missing) ;
+       }
+       Z = (Entry *) (SolveWork + 4*n) ;       /* Entry Z [0..n-1] */
+       S = (Entry *) (SolveWork + 6*n) ;       /* Entry S [0..n-1] */
+       Y = (double *) (SolveWork + 8*n) ;      /* double Y [0..n-1] */
+       B2 = (double *) (SolveWork + 9*n) ;     /* double B2 [0..n-1] */
+       Z2 = (double *) Z ;             /* double Z2 [0..n-1], equiv. to Z */
+    }
+#else
+    X = (Entry *) Xx ;                         /* Entry X [0..n-1] */
+    if (irstep > 0)
+    {
+       if (!Ap || !Ai || !Ax)
+       {
+           return (UMFPACK_ERROR_argument_missing) ;
+       }
+       Z = (Entry *) (SolveWork + n) ;         /* Entry Z [0..n-1] */
+       S = (Entry *) (SolveWork + 2*n) ;       /* Entry S [0..n-1] */
+       Y = (double *) (SolveWork + 3*n) ;      /* double Y [0..n-1] */
+       B2 = (double *) (SolveWork + 4*n) ;     /* double B2 [0..n-1] */
+       Z2 = (double *) Z ;             /* double Z2 [0..n-1], equiv. to Z */
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* determine which system to solve */
+    /* ---------------------------------------------------------------------- */
+
+    if (sys == UMFPACK_A)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* solve A x = b with optional iterative refinement */
+       /* ------------------------------------------------------------------ */
+
+       if (irstep > 0)
+       {
+
+           /* -------------------------------------------------------------- */
+           /* using iterative refinement:  compute Y and B2 */
+           /* -------------------------------------------------------------- */
+
+           nz = Ap [n] ;
+           Info [UMFPACK_NZ] = nz ;
+
+           /* A is stored by column */
+           /* Y (i) = ||R A_i||, 1-norm of row i of R A */
+           for (i = 0 ; i < n ; i++)
+           {
+               Y [i] = 0. ;
+           }
+           flops += (ABS_FLOPS + 1) * nz ;
+           p2 = Ap [n] ;
+           for (p = 0 ; p < p2 ; p++)
+           {
+               /* Y [Ai [p]] += ABS (Ax [p]) ; */
+               ASSIGN (aij, Ax [p], Az [p]) ;
+               ABS (d, aij) ;
+               Y [Ai [p]] += d ;
+           }
+
+           /* B2 = abs (B) */
+           flops += ABS_FLOPS * n ;
+           for (i = 0 ; i < n ; i++)
+           {
+               /* B2 [i] = ABS (B [i]) ; */
+               ASSIGN (bi, Bx [i], Bz [i]) ;
+               ABS (B2 [i], bi) ;
+           }
+
+           /* scale Y and B2. */
+           if (do_scale)
+           {
+               /* Y = R Y */
+               /* B2 = R B2 */
+#ifndef NRECIPROCAL
+               if (do_recip)
+               {
+                   /* multiply by the scale factors */
+                   for (i = 0 ; i < n ; i++)
+                   {
+                       Y [i]  *= Rs [i] ;
+                       B2 [i] *= Rs [i] ;
+                   }
+               }
+               else
+#endif
+               {
+                   /* divide by the scale factors */
+                   for (i = 0 ; i < n ; i++)
+                   {
+                       Y [i]  /= Rs [i] ;
+                       B2 [i] /= Rs [i] ;
+                   }
+               }
+
+               flops += 2 * n ;
+           }
+
+       }
+
+       for (step = 0 ; step <= irstep ; step++)
+       {
+
+           /* -------------------------------------------------------------- */
+           /* Solve A x = b (step 0): */
+           /*  x = Q (U \ (L \ (P R b))) */
+           /* and then perform iterative refinement (step > 0): */
+           /*  x = x + Q (U \ (L \ (P R (b - A x)))) */
+           /* -------------------------------------------------------------- */
+
+           if (step == 0)
+           {
+               if (do_scale)
+               {
+                   /* W = P R b, using X as workspace, since Z is not
+                    * allocated if irstep = 0. */
+#ifndef NRECIPROCAL
+                   if (do_recip)
+                   {
+                       /* multiply by the scale factors */
+                       for (i = 0 ; i < n ; i++)
+                       {
+                           ASSIGN (X [i], Bx [i], Bz [i]) ;
+                           SCALE_RECIP (X [i], Rs [i]) ;
+                       }
+                   }
+                   else
+#endif
+                   {
+                       /* divide by the scale factors */
+                       for (i = 0 ; i < n ; i++)
+                       {
+                           ASSIGN (X [i], Bx [i], Bz [i]) ;
+                           SCALE_DIV (X [i], Rs [i]) ;
+                       }
+                   }
+                   flops += SCALE_FLOPS * n ;
+                   for (i = 0 ; i < n ; i++)
+                   {
+                       W [i] = X [Rperm [i]] ;
+                   }
+               }
+               else
+               {
+                   /* W = P b, since the row scaling R = I */
+                   for (i = 0 ; i < n ; i++)
+                   {
+                       /* W [i] = B [Rperm [i]] ; */
+                       ASSIGN (W [i], Bx [Rperm [i]], Bz [Rperm [i]]) ;
+                   }
+               }
+           }
+           else
+           {
+               for (i = 0 ; i < n ; i++)
+               {
+                   /* Z [i] = B [i] ; */
+                   ASSIGN (Z [i], Bx [i], Bz [i]) ;
+               }
+               flops += MULTSUB_FLOPS * nz ;
+               for (i = 0 ; i < n ; i++)
+               {
+                   xi = X [i] ;
+                   p2 = Ap [i+1] ;
+                   for (p = Ap [i] ; p < p2 ; p++)
+                   {
+                       /* Z [Ai [p]] -= Ax [p] * xi ; */
+                       ASSIGN (aij, Ax [p], Az [p]) ;
+                       MULT_SUB (Z [Ai [p]], aij, xi) ;
+                   }
+               }
+               /* scale, Z = R Z */
+               if (do_scale)
+               {
+#ifndef NRECIPROCAL
+                   if (do_recip)
+                   {
+                       /* multiply by the scale factors */
+                       for (i = 0 ; i < n ; i++)
+                       {
+                           SCALE_RECIP (Z [i], Rs [i]) ;
+                       }
+                   }
+                   else
+#endif
+                   {
+                       /* divide by the scale factors */
+                       for (i = 0 ; i < n ; i++)
+                       {
+                           SCALE_DIV (Z [i], Rs [i]) ;
+                       }
+                   }
+                   flops += SCALE_FLOPS * n ;
+               }
+               for (i = 0 ; i < n ; i++)
+               {
+                   W [i] = Z [Rperm [i]] ;
+               }
+           }
+
+           flops += UMF_lsolve (Numeric, W, Pattern) ;
+           flops += UMF_usolve (Numeric, W, Pattern) ;
+
+           if (step == 0)
+           {
+               for (i = 0 ; i < n ; i++)
+               {
+                   X [Cperm [i]] = W [i] ;
+               }
+           }
+           else
+           {
+               flops += ASSEMBLE_FLOPS * n ;
+               for (i = 0 ; i < n ; i++)
+               {
+                   /* X [Cperm [i]] += W [i] ; */
+                   ASSEMBLE (X [Cperm [i]], W [i]) ;
+               }
+           }
+
+           /* -------------------------------------------------------------- */
+           /* sparse backward error estimate */
+           /* -------------------------------------------------------------- */
+
+           if (irstep > 0)
+           {
+
+               /* ---------------------------------------------------------- */
+               /* A is stored by column */
+               /* W (i) = R (b - A x)_i, residual */
+               /* Z2 (i) = R (|A||x|)_i */
+               /* ---------------------------------------------------------- */
+
+               for (i = 0 ; i < n ; i++)
+               {
+                   /* W [i] = B [i] ; */
+                   ASSIGN (W [i], Bx [i], Bz [i]) ;
+                   Z2 [i] = 0. ;
+               }
+               flops += (MULT_FLOPS + DECREMENT_FLOPS + ABS_FLOPS + 1) * nz ;
+               for (j = 0 ; j < n ; j++)
+               {
+                   xj = X [j] ;
+                   p2 = Ap [j+1] ;
+                   for (p = Ap [j] ; p < p2 ; p++)
+                   {
+                       i = Ai [p] ;
+
+                       /* axx = Ax [p] * xj ; */
+                       ASSIGN (aij, Ax [p], Az [p]) ;
+                       MULT (axx, aij, xj) ;
+
+                       /* W [i] -= axx ; */
+                       DECREMENT (W [i], axx) ;
+
+                       /* Z2 [i] += ABS (axx) ; */
+                       ABS (d, axx) ;
+                       Z2 [i] += d ;
+                   }
+               }
+
+               /* scale W and Z2 */
+               if (do_scale)
+               {
+                   /* Z2 = R Z2 */
+                   /* W = R W */
+#ifndef NRECIPROCAL
+                   if (do_recip)
+                   {
+                       /* multiply by the scale factors */
+                       for (i = 0 ; i < n ; i++)
+                       {
+                           SCALE_RECIP (W [i], Rs [i]) ;
+                           Z2 [i] *= Rs [i] ;
+                       }
+                   }
+                   else
+#endif
+                   {
+                       /* divide by the scale factors */
+                       for (i = 0 ; i < n ; i++)
+                       {
+                           SCALE_DIV (W [i], Rs [i]) ;
+                           Z2 [i] /= Rs [i] ;
+                       }
+                   }
+                   flops += (SCALE_FLOPS + 1) * n ;
+               }
+
+               flops += (2*ABS_FLOPS + 5) * n ;
+               if (do_step (omega, step, B2, X, W, Y, Z2, S, n, Info))
+               {
+                   /* iterative refinement is done */
+                   break ;
+               }
+
+           }
+
+       }
+
+    }
+    else if (sys == UMFPACK_At)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* solve A' x = b with optional iterative refinement */
+       /* ------------------------------------------------------------------ */
+
+       /* A' is the complex conjugate transpose */
+
+       if (irstep > 0)
+       {
+
+           /* -------------------------------------------------------------- */
+           /* using iterative refinement:  compute Y */
+           /* -------------------------------------------------------------- */
+
+           nz = Ap [n] ;
+           Info [UMFPACK_NZ] = nz ;
+
+           /* A' is stored by row */
+           /* Y (i) = ||(A' R)_i||, 1-norm of row i of A' R */
+
+           if (do_scale)
+           {
+               flops += (ABS_FLOPS + 2) * nz ;
+#ifndef NRECIPROCAL
+               if (do_recip)
+               {
+                   /* multiply by the scale factors */
+                   for (i = 0 ; i < n ; i++)
+                   {
+                       yi = 0. ;
+                       p2 = Ap [i+1] ;
+                       for (p = Ap [i] ; p < p2 ; p++)
+                       {
+                           /* yi += ABS (Ax [p]) * Rs [Ai [p]] ; */
+                           /* note that abs (aij) is the same as
+                            * abs (conj (aij)) */
+                           ASSIGN (aij, Ax [p], Az [p]) ;
+                           ABS (d, aij) ;
+                           yi += (d * Rs [Ai [p]]) ;
+                       }
+                       Y [i] = yi ;
+                   }
+               }
+               else
+#endif
+               {
+                   /* divide by the scale factors */
+                   for (i = 0 ; i < n ; i++)
+                   {
+                       yi = 0. ;
+                       p2 = Ap [i+1] ;
+                       for (p = Ap [i] ; p < p2 ; p++)
+                       {
+                           /* yi += ABS (Ax [p]) / Rs [Ai [p]] ; */
+                           /* note that abs (aij) is the same as
+                            * abs (conj (aij)) */
+                           ASSIGN (aij, Ax [p], Az [p]) ;
+                           ABS (d, aij) ;
+                           yi += (d / Rs [Ai [p]]) ;
+                       }
+                       Y [i] = yi ;
+                   }
+               }
+           }
+           else
+           {
+               /* no scaling */
+               flops += (ABS_FLOPS + 1) * nz ;
+               for (i = 0 ; i < n ; i++)
+               {
+                   yi = 0. ;
+                   p2 = Ap [i+1] ;
+                   for (p = Ap [i] ; p < p2 ; p++)
+                   {
+                       /* yi += ABS (Ax [p]) ; */
+                       /* note that abs (aij) is the same as
+                        * abs (conj (aij)) */
+                       ASSIGN (aij, Ax [p], Az [p]) ;
+                       ABS (d, aij) ;
+                       yi += d ;
+                   }
+                   Y [i] = yi ;
+               }
+           }
+
+           /* B2 = abs (B) */
+           for (i = 0 ; i < n ; i++)
+           {
+               /* B2 [i] = ABS (B [i]) ; */
+               ASSIGN (bi, Bx [i], Bz [i]) ;
+               ABS (B2 [i], bi) ;
+           }
+
+       }
+
+       for (step = 0 ; step <= irstep ; step++)
+       {
+
+           /* -------------------------------------------------------------- */
+           /* Solve A' x = b (step 0): */
+           /*  x = R P' (L' \ (U' \ (Q' b))) */
+           /* and then perform iterative refinement (step > 0): */
+           /*  x = x + R P' (L' \ (U' \ (Q' (b - A' x)))) */
+           /* -------------------------------------------------------------- */
+
+           if (step == 0)
+           {
+               /* W = Q' b */
+               for (i = 0 ; i < n ; i++)
+               {
+                   /* W [i] = B [Cperm [i]] ; */
+                   ASSIGN (W [i], Bx [Cperm [i]], Bz [Cperm [i]]) ;
+               }
+           }
+           else
+           {
+               /* Z = b - A' x */
+               for (i = 0 ; i < n ; i++)
+               {
+                   /* Z [i] = B [i] ; */
+                   ASSIGN (Z [i], Bx [i], Bz [i]) ;
+               }
+               flops += MULTSUB_FLOPS * nz ;
+               for (i = 0 ; i < n ; i++)
+               {
+                   zi = Z [i] ;
+                   p2 = Ap [i+1] ;
+                   for (p = Ap [i] ; p < p2 ; p++)
+                   {
+                       /* zi -= conjugate (Ax [p]) * X [Ai [p]] ; */
+                       ASSIGN (aij, Ax [p], Az [p]) ;
+                       MULT_SUB_CONJ (zi, X [Ai [p]], aij) ;
+                   }
+                   Z [i] = zi ;
+               }
+               /* W = Q' Z */
+               for (i = 0 ; i < n ; i++)
+               {
+                   W [i] = Z [Cperm [i]] ;
+               }
+           }
+
+           flops += UMF_uhsolve (Numeric, W, Pattern) ;
+           flops += UMF_lhsolve (Numeric, W, Pattern) ;
+
+           if (step == 0)
+           {
+
+               /* X = R P' W */
+               /* do not use Z, since it isn't allocated if irstep = 0 */
+
+               /* X = P' W */
+               for (i = 0 ; i < n ; i++)
+               {
+                   X [Rperm [i]] = W [i] ;
+               }
+               if (do_scale)
+               {
+                   /* X = R X */
+#ifndef NRECIPROCAL
+                   if (do_recip)
+                   {
+                       /* multiply by the scale factors */
+                       for (i = 0 ; i < n ; i++)
+                       {
+                           SCALE_RECIP (X [i], Rs [i]) ;
+                       }
+                   }
+                   else
+#endif
+                   {
+                       /* divide by the scale factors */
+                       for (i = 0 ; i < n ; i++)
+                       {
+                           SCALE_DIV (X [i], Rs [i]) ;
+                       }
+                   }
+                   flops += SCALE_FLOPS * n ;
+               }
+
+           }
+           else
+           {
+
+               /* Z = P' W */
+               for (i = 0 ; i < n ; i++)
+               {
+                   Z [Rperm [i]] = W [i] ;
+               }
+               if (do_scale)
+               {
+                   /* Z = R Z */
+#ifndef NRECIPROCAL
+                   if (do_recip)
+                   {
+                       /* multiply by the scale factors */
+                       for (i = 0 ; i < n ; i++)
+                       {
+                           SCALE_RECIP (Z [i], Rs [i]) ;
+                       }
+                   }
+                   else
+#endif
+                   {
+                       /* divide by the scale factors */
+                       for (i = 0 ; i < n ; i++)
+                       {
+                           SCALE_DIV (Z [i], Rs [i]) ;
+                       }
+                   }
+                   flops += SCALE_FLOPS * n ;
+               }
+
+               flops += ASSEMBLE_FLOPS * n ;
+               /* X += Z */
+               for (i = 0 ; i < n ; i++)
+               {
+                   /* X [i] += W [i] ; */
+                   ASSEMBLE (X [i], W [i]) ;
+               }
+           }
+
+           /* -------------------------------------------------------------- */
+           /* sparse backward error estimate */
+           /* -------------------------------------------------------------- */
+
+           if (irstep > 0)
+           {
+
+               /* ---------------------------------------------------------- */
+               /* A' is stored by row */
+               /* W (i) = (b - A' x)_i, residual */
+               /* Z2 (i) = (|A'||x|)_i */
+               /* ---------------------------------------------------------- */
+
+               flops += (MULT_FLOPS + DECREMENT_FLOPS + ABS_FLOPS + 1) * nz ;
+               for (i = 0 ; i < n ; i++)
+               {
+                   /* wi = B [i] ; */
+                   ASSIGN (wi, Bx [i], Bz [i]) ;
+                   z2i = 0. ;
+                   p2 = Ap [i+1] ;
+                   for (p = Ap [i] ; p < p2 ; p++)
+                   {
+                       /* axx = conjugate (Ax [p]) * X [Ai [p]] ; */
+                       ASSIGN (aij, Ax [p], Az [p]) ;
+                       MULT_CONJ (axx, X [Ai [p]], aij) ;
+
+                       /* wi -= axx ; */
+                       DECREMENT (wi, axx) ;
+
+                       /* z2i += ABS (axx) ; */
+                       ABS (d, axx) ;
+                       z2i += d ;
+                   }
+                   W [i] = wi ;
+                   Z2 [i] = z2i ;
+               }
+
+               flops += (2*ABS_FLOPS + 5) * n ;
+               if (do_step (omega, step, B2, X, W, Y, Z2, S, n, Info))
+               {
+                   /* iterative refinement is done */
+                   break ;
+               }
+
+           }
+
+       }
+
+    }
+    else if (sys == UMFPACK_Aat)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* solve A.' x = b with optional iterative refinement */
+       /* ------------------------------------------------------------------ */
+
+       /* A' is the array transpose */
+
+       if (irstep > 0)
+       {
+
+           /* -------------------------------------------------------------- */
+           /* using iterative refinement:  compute Y */
+           /* -------------------------------------------------------------- */
+
+           nz = Ap [n] ;
+           Info [UMFPACK_NZ] = nz ;
+
+           /* A.' is stored by row */
+           /* Y (i) = ||(A.' R)_i||, 1-norm of row i of A.' R */
+
+           if (do_scale)
+           {
+               flops += (ABS_FLOPS + 2) * nz ;
+#ifndef NRECIPROCAL
+               if (do_recip)
+               {
+                   /* multiply by the scale factors */
+                   for (i = 0 ; i < n ; i++)
+                   {
+                       yi = 0. ;
+                       p2 = Ap [i+1] ;
+                       for (p = Ap [i] ; p < p2 ; p++)
+                       {
+                           /* yi += ABS (Ax [p]) * Rs [Ai [p]] ; */
+                           /* note that A.' is the array transpose,
+                            * so no conjugate */
+                           ASSIGN (aij, Ax [p], Az [p]) ;
+                           ABS (d, aij) ;
+                           yi += (d * Rs [Ai [p]]) ;
+                       }
+                       Y [i] = yi ;
+                   }
+               }
+               else
+#endif
+               {
+                   /* divide by the scale factors */
+                   for (i = 0 ; i < n ; i++)
+                   {
+                       yi = 0. ;
+                       p2 = Ap [i+1] ;
+                       for (p = Ap [i] ; p < p2 ; p++)
+                       {
+                           /* yi += ABS (Ax [p]) / Rs [Ai [p]] ; */
+                           /* note that A.' is the array transpose,
+                            * so no conjugate */
+                           ASSIGN (aij, Ax [p], Az [p]) ;
+                           ABS (d, aij) ;
+                           yi += (d / Rs [Ai [p]]) ;
+                       }
+                       Y [i] = yi ;
+                   }
+               }
+           }
+           else
+           {
+               /* no scaling */
+               flops += (ABS_FLOPS + 1) * nz ;
+               for (i = 0 ; i < n ; i++)
+               {
+                   yi = 0. ;
+                   p2 = Ap [i+1] ;
+                   for (p = Ap [i] ; p < p2 ; p++)
+                   {
+                       /* yi += ABS (Ax [p]) */
+                       /* note that A.' is the array transpose,
+                        * so no conjugate */
+                       ASSIGN (aij, Ax [p], Az [p]) ;
+                       ABS (d, aij) ;
+                       yi += d ;
+                   }
+                   Y [i] = yi ;
+               }
+           }
+
+           /* B2 = abs (B) */
+           for (i = 0 ; i < n ; i++)
+           {
+               /* B2 [i] = ABS (B [i]) ; */
+               ASSIGN (bi, Bx [i], Bz [i]) ;
+               ABS (B2 [i], bi) ;
+           }
+
+       }
+
+       for (step = 0 ; step <= irstep ; step++)
+       {
+
+           /* -------------------------------------------------------------- */
+           /* Solve A.' x = b (step 0): */
+           /*  x = R P' (L.' \ (U.' \ (Q' b))) */
+           /* and then perform iterative refinement (step > 0): */
+           /*  x = x + R P' (L.' \ (U.' \ (Q' (b - A.' x)))) */
+           /* -------------------------------------------------------------- */
+
+           if (step == 0)
+           {
+               /* W = Q' b */
+               for (i = 0 ; i < n ; i++)
+               {
+                   /* W [i] = B [Cperm [i]] ; */
+                   ASSIGN (W [i], Bx [Cperm [i]], Bz [Cperm [i]]) ;
+               }
+           }
+           else
+           {
+               /* Z = b - A.' x */
+               for (i = 0 ; i < n ; i++)
+               {
+                   /* Z [i] = B [i] ; */
+                   ASSIGN (Z [i], Bx [i], Bz [i]) ;
+               }
+               flops += MULTSUB_FLOPS * nz ;
+               for (i = 0 ; i < n ; i++)
+               {
+                   zi = Z [i] ;
+                   p2 = Ap [i+1] ;
+                   for (p = Ap [i] ; p < p2 ; p++)
+                   {
+                       /* zi -= Ax [p] * X [Ai [p]] ; */
+                       ASSIGN (aij, Ax [p], Az [p]) ;
+                       MULT_SUB (zi, aij, X [Ai [p]]) ;
+                   }
+                   Z [i] = zi ;
+               }
+               /* W = Q' Z */
+               for (i = 0 ; i < n ; i++)
+               {
+                   W [i] = Z [Cperm [i]] ;
+               }
+           }
+
+           flops += UMF_utsolve (Numeric, W, Pattern) ;
+           flops += UMF_ltsolve (Numeric, W, Pattern) ;
+
+           if (step == 0)
+           {
+
+               /* X = R P' W */
+               /* do not use Z, since it isn't allocated if irstep = 0 */
+
+               /* X = P' W */
+               for (i = 0 ; i < n ; i++)
+               {
+                   X [Rperm [i]] = W [i] ;
+               }
+               if (do_scale)
+               {
+                   /* X = R X */
+#ifndef NRECIPROCAL
+                   if (do_recip)
+                   {
+                       /* multiply by the scale factors */
+                       for (i = 0 ; i < n ; i++)
+                       {
+                           SCALE_RECIP (X [i], Rs [i]) ;
+                       }
+                   }
+                   else
+#endif
+                   {
+                       /* divide by the scale factors */
+                       for (i = 0 ; i < n ; i++)
+                       {
+                           SCALE_DIV (X [i], Rs [i]) ;
+                       }
+                   }
+                   flops += SCALE_FLOPS * n ;
+               }
+
+           }
+           else
+           {
+
+               /* Z = P' W */
+               for (i = 0 ; i < n ; i++)
+               {
+                   Z [Rperm [i]] = W [i] ;
+               }
+               if (do_scale)
+               {
+                   /* Z = R Z */
+#ifndef NRECIPROCAL
+                   if (do_recip)
+                   {
+                       /* multiply by the scale factors */
+                       for (i = 0 ; i < n ; i++)
+                       {
+                           SCALE_RECIP (Z [i], Rs [i]) ;
+                       }
+                   }
+                   else
+#endif
+                   {
+                       /* divide by the scale factors */
+                       for (i = 0 ; i < n ; i++)
+                       {
+                           SCALE_DIV (Z [i], Rs [i]) ;
+                       }
+                   }
+                   flops += SCALE_FLOPS * n ;
+               }
+
+               flops += ASSEMBLE_FLOPS * n ;
+               /* X += Z */
+               for (i = 0 ; i < n ; i++)
+               {
+                   /* X [i] += W [i] ; */
+                   ASSEMBLE (X [i], W [i]) ;
+               }
+           }
+
+           /* -------------------------------------------------------------- */
+           /* sparse backward error estimate */
+           /* -------------------------------------------------------------- */
+
+           if (irstep > 0)
+           {
+
+               /* ---------------------------------------------------------- */
+               /* A.' is stored by row */
+               /* W (i) = (b - A.' x)_i, residual */
+               /* Z (i) = (|A.'||x|)_i */
+               /* ---------------------------------------------------------- */
+
+               flops += (MULT_FLOPS + DECREMENT_FLOPS + ABS_FLOPS + 1) * nz ;
+               for (i = 0 ; i < n ; i++)
+               {
+                   /* wi = B [i] ; */
+                   ASSIGN (wi, Bx [i], Bz [i]) ;
+                   z2i = 0. ;
+                   p2 = Ap [i+1] ;
+                   for (p = Ap [i] ; p < p2 ; p++)
+                   {
+                       /* axx = Ax [p] * X [Ai [p]] ; */
+                       ASSIGN (aij, Ax [p], Az [p]) ;
+                       MULT (axx, aij, X [Ai [p]]) ;
+
+                       /* wi -= axx ; */
+                       DECREMENT (wi, axx) ;
+
+                       /* z2i += ABS (axx) ; */
+                       ABS (d, axx) ;
+                       z2i += d ;
+                   }
+                   W [i] = wi ;
+                   Z2 [i] = z2i ;
+               }
+
+               flops += (2*ABS_FLOPS + 5) * n ;
+               if (do_step (omega, step, B2, X, W, Y, Z2, S, n, Info))
+               {
+                   /* iterative refinement is done */
+                   break ;
+               }
+
+           }
+
+       }
+
+    }
+    else if (sys == UMFPACK_Pt_L)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* Solve P'Lx=b:  x = L \ Pb */
+       /* ------------------------------------------------------------------ */
+
+       for (i = 0 ; i < n ; i++)
+       {
+           /* X [i] = B [Rperm [i]] ; */
+           ASSIGN (X [i], Bx [Rperm [i]], Bz [Rperm [i]]) ;
+       }
+       flops = UMF_lsolve (Numeric, X, Pattern) ;
+       status = UMFPACK_OK ;
+
+    }
+    else if (sys == UMFPACK_L)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* Solve Lx=b:  x = L \ b */
+       /* ------------------------------------------------------------------ */
+
+       for (i = 0 ; i < n ; i++)
+       {
+           /* X [i] = B [i] ; */
+           ASSIGN (X [i], Bx [i], Bz [i]) ;
+       }
+       flops = UMF_lsolve (Numeric, X, Pattern) ;
+       status = UMFPACK_OK ;
+
+    }
+    else if (sys == UMFPACK_Lt_P)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* Solve L'Px=b:  x = P' (L' \ b) */
+       /* ------------------------------------------------------------------ */
+
+       for (i = 0 ; i < n ; i++)
+       {
+           /* W [i] = B [i] ; */
+           ASSIGN (W [i], Bx [i], Bz [i]) ;
+       }
+       flops = UMF_lhsolve (Numeric, W, Pattern) ;
+       for (i = 0 ; i < n ; i++)
+       {
+           X [Rperm [i]] = W [i] ;
+       }
+       status = UMFPACK_OK ;
+
+    }
+    else if (sys == UMFPACK_Lat_P)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* Solve L.'Px=b:  x = P' (L.' \ b) */
+       /* ------------------------------------------------------------------ */
+
+       for (i = 0 ; i < n ; i++)
+       {
+           /* W [i] = B [i] ; */
+           ASSIGN (W [i], Bx [i], Bz [i]) ;
+       }
+       flops = UMF_ltsolve (Numeric, W, Pattern) ;
+       for (i = 0 ; i < n ; i++)
+       {
+           X [Rperm [i]] = W [i] ;
+       }
+       status = UMFPACK_OK ;
+
+    }
+    else if (sys == UMFPACK_Lt)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* Solve L'x=b:  x = L' \ b */
+       /* ------------------------------------------------------------------ */
+
+       for (i = 0 ; i < n ; i++)
+       {
+           /* X [i] = B [i] ; */
+           ASSIGN (X [i], Bx [i], Bz [i]) ;
+       }
+       flops = UMF_lhsolve (Numeric, X, Pattern) ;
+       status = UMFPACK_OK ;
+
+    }
+    else if (sys == UMFPACK_Lat)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* Solve L.'x=b:  x = L.' \ b */
+       /* ------------------------------------------------------------------ */
+
+       for (i = 0 ; i < n ; i++)
+       {
+           /* X [i] = B [i] ; */
+           ASSIGN (X [i], Bx [i], Bz [i]) ;
+       }
+       flops = UMF_ltsolve (Numeric, X, Pattern) ;
+       status = UMFPACK_OK ;
+
+    }
+    else if (sys == UMFPACK_U_Qt)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* Solve UQ'x=b:  x = Q (U \ b) */
+       /* ------------------------------------------------------------------ */
+
+       for (i = 0 ; i < n ; i++)
+       {
+           /* W [i] = B [i] ; */
+           ASSIGN (W [i], Bx [i], Bz [i]) ;
+       }
+       flops = UMF_usolve (Numeric, W, Pattern) ;
+       for (i = 0 ; i < n ; i++)
+       {
+           X [Cperm [i]] = W [i] ;
+       }
+
+    }
+    else if (sys == UMFPACK_U)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* Solve Ux=b:  x = U \ b */
+       /* ------------------------------------------------------------------ */
+
+       for (i = 0 ; i < n ; i++)
+       {
+           /* X [i] = B [i] ; */
+           ASSIGN (X [i], Bx [i], Bz [i]) ;
+       }
+       flops = UMF_usolve (Numeric, X, Pattern) ;
+
+    }
+    else if (sys == UMFPACK_Q_Ut)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* Solve QU'x=b:  x = U' \ Q'b */
+       /* ------------------------------------------------------------------ */
+
+       for (i = 0 ; i < n ; i++)
+       {
+           /* X [i] = B [Cperm [i]] ; */
+           ASSIGN (X [i], Bx [Cperm [i]], Bz [Cperm [i]]) ;
+       }
+       flops = UMF_uhsolve (Numeric, X, Pattern) ;
+
+    }
+    else if (sys == UMFPACK_Q_Uat)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* Solve QU.'x=b:  x = U.' \ Q'b */
+       /* ------------------------------------------------------------------ */
+
+       for (i = 0 ; i < n ; i++)
+       {
+           /* X [i] = B [Cperm [i]] ; */
+           ASSIGN (X [i], Bx [Cperm [i]], Bz [Cperm [i]]) ;
+       }
+       flops = UMF_utsolve (Numeric, X, Pattern) ;
+
+    }
+    else if (sys == UMFPACK_Ut)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* Solve U'x=b:  x = U' \ b */
+       /* ------------------------------------------------------------------ */
+
+       for (i = 0 ; i < n ; i++)
+       {
+           /* X [i] = B [i] ; */
+           ASSIGN (X [i], Bx [i], Bz [i]) ;
+       }
+       flops = UMF_uhsolve (Numeric, X, Pattern) ;
+
+    }
+    else if (sys == UMFPACK_Uat)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* Solve U'x=b:  x = U' \ b */
+       /* ------------------------------------------------------------------ */
+
+       for (i = 0 ; i < n ; i++)
+       {
+           /* X [i] = B [i] ; */
+           ASSIGN (X [i], Bx [i], Bz [i]) ;
+       }
+       flops = UMF_utsolve (Numeric, X, Pattern) ;
+
+    }
+    else
+    {
+       return (UMFPACK_ERROR_invalid_system) ;
+    }
+
+#ifdef COMPLEX
+    /* copy the solution back, from Entry X [ ] to double Xx [ ] and Xz [ ] */
+    for (i = 0 ; i < n ; i++)
+    {
+       Xx [i] = REAL_COMPONENT (X [i]) ;
+       Xz [i] = IMAG_COMPONENT (X [i]) ;
+    }
+#endif
+
+    /* return UMFPACK_OK, or UMFPACK_WARNING_singular_matrix */
+    /* Note that systems involving just L will return UMFPACK_OK */
+    Info [UMFPACK_SOLVE_FLOPS] = flops ;
+    return (status) ;
+}
+
+
+/* ========================================================================== */
+/* === do_step ============================================================== */
+/* ========================================================================== */
+
+/* Perform one step of iterative refinement, for A x = b or A' x = b */
+
+PRIVATE Int do_step            /* return TRUE if iterative refinement done */
+(
+    double omega [3],
+    Int step,                  /* which step of iterative refinement to do */
+    const double B2 [ ],       /* abs (B) */
+    Entry X [ ],
+    const Entry W [ ],
+    const double Y [ ],
+    const double Z2 [ ],
+    Entry S [ ],
+    Int n,
+    double Info [UMFPACK_INFO]
+)
+{
+    double last_omega [3], tau, nctau, d1, wd1, d2, wd2, xi, yix, wi, xnorm ;
+    Int i ;
+
+    /* DBL_EPSILON is a standard ANSI C term defined in <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/deal.II/contrib/umfpack/UMFPACK/Source/umf_solve.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_solve.h
new file mode 100644 (file)
index 0000000..35a4867
--- /dev/null
@@ -0,0 +1,26 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_solve
+(
+    Int sys,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const double Ax [ ],
+    double Xx [ ],
+    const double Bx [ ],
+#ifdef COMPLEX
+    const double Az [ ],
+    double Xz [ ],
+    const double Bz [ ],
+#endif
+    NumericType *Numeric,
+    Int irstep,
+    double Info [UMFPACK_INFO],
+    Int Pattern [ ],
+    double SolveWork [ ]
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_start_front.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_start_front.c
new file mode 100644 (file)
index 0000000..bb34a93
--- /dev/null
@@ -0,0 +1,284 @@
+/* ========================================================================== */
+/* === UMF_start_front ====================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* Allocate the initial frontal matrix working array for a single chain.  The
+ * front does not have to be big enough, since if it's too small it will get
+ * reallocated.  The size computed here is just an estimate. */
+
+#include "umf_internal.h"
+#include "umf_grow_front.h"
+
+GLOBAL Int UMF_start_front    /* returns TRUE if successful, FALSE otherwise */
+(
+    Int chain,
+    NumericType *Numeric,
+    WorkType *Work,
+    SymbolicType *Symbolic
+)
+{
+    Int fnrows_max, fncols_max, fnr2, fnc2, fsize, fcurr_size, maxfrsize,
+       overflow, nb, f, cdeg ;
+    double maxbytes ;
+
+    nb = Symbolic->nb ;
+    fnrows_max = Symbolic->Chain_maxrows [chain] ;
+    fncols_max = Symbolic->Chain_maxcols [chain] ;
+
+    DEBUGm2 (("Start Front for chain "ID".  fnrows_max "ID" fncols_max "ID"\n",
+       chain, fnrows_max, fncols_max)) ;
+
+    Work->fnrows_max = fnrows_max ;
+    Work->fncols_max = fncols_max ;
+    Work->any_skip = FALSE ;
+
+    maxbytes = sizeof (Entry) *
+       (double) (fnrows_max + nb) * (double) (fncols_max + nb) ;
+    fcurr_size = Work->fcurr_size ;
+
+    if (Symbolic->prefer_diagonal)
+    {
+       /* Get a rough upper bound on the degree of the first pivot column in
+        * this front.  Note that Col_degree is not maintained if diagonal
+        * pivoting is preferred.  For most matrices, the first pivot column
+        * of the first frontal matrix of a new chain has only one tuple in
+        * it anyway, so this bound is exact in that case. */
+       Int col, tpi, e, *E, *Col_tuples, *Col_tlen, *Cols ;
+       Tuple *tp, *tpend ;
+       Unit *Memory, *p ;
+       Element *ep ;
+       E = Work->E ;
+       Memory = Numeric->Memory ;
+       Col_tuples = Numeric->Lip ;
+       Col_tlen = Numeric->Lilen ;
+       col = Work->nextcand ;
+       tpi = Col_tuples [col] ;
+       tp = (Tuple *) Memory + tpi ;
+       tpend = tp + Col_tlen [col] ;
+       cdeg = 0 ;
+       DEBUGm3 (("\n=============== start front: col "ID" tlen "ID"\n",
+               col, Col_tlen [col])) ;
+       for ( ; tp < tpend ; tp++)
+       {
+           DEBUG1 (("Tuple ("ID","ID")\n", tp->e, tp->f)) ;
+           e = tp->e ;
+           if (!E [e]) continue ;
+           f = tp->f ;
+           p = Memory + E [e] ;
+           ep = (Element *) p ;
+           p += UNITS (Element, 1) ;
+           Cols = (Int *) p ;
+           if (Cols [f] == EMPTY) continue ;
+           DEBUG1 (("  nrowsleft "ID"\n", ep->nrowsleft)) ;
+           cdeg += ep->nrowsleft ;
+       }
+#ifndef NDEBUG
+       DEBUGm3 (("start front cdeg: "ID" col "ID"\n", cdeg, col)) ;
+       UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ;
+#endif
+
+       /* cdeg is now the rough upper bound on the degree of the next pivot
+        * column. */
+
+       /* If AMD was called, we know the maximum number of nonzeros in any
+        * column of L.  Use this as an upper bound for cdeg, but add 2 to
+        * account for a small amount of off-diagonal pivoting. */
+       if (Symbolic->amd_dmax > 0)
+       {
+           cdeg = MIN (cdeg, Symbolic->amd_dmax) ;
+       }
+
+       /* Increase it to account for larger columns later on.
+        * Also ensure that it's larger than zero. */
+       cdeg += 2 ;
+
+       /* cdeg cannot be larger than fnrows_max */
+       cdeg = MIN (cdeg, fnrows_max) ;
+
+    }
+    else
+    {
+       /* don't do the above cdeg computation */
+       cdeg = 0 ;
+    }
+
+    DEBUGm2 (("fnrows max "ID" fncols_max "ID"\n", fnrows_max, fncols_max)) ;
+
+    /* the current frontal matrix is empty */
+    ASSERT (Work->fnrows == 0 && Work->fncols == 0 && Work->fnpiv == 0) ;
+
+    /* maximum row dimension is always odd, to avoid bad cache effects */
+    ASSERT (fnrows_max >= 0) ;
+    ASSERT (fnrows_max % 2 == 1) ;
+
+    /* ----------------------------------------------------------------------
+     * allocate working array for current frontal matrix:
+     * minimum size: 1-by-1
+     * maximum size: fnrows_max-by-fncols_max
+     * desired size:
+     *
+     *   if Numeric->front_alloc_init >= 0:
+     *
+     *     for unsymmetric matrices:
+     *     Numeric->front_alloc_init * (fnrows_max-by-fncols_max)
+     *
+     *     for symmetric matrices (diagonal pivoting preference, actually):
+     *     Numeric->front_alloc_init * (fnrows_max-by-fncols_max), or
+     *     cdeg*cdeg, whichever is smaller.
+     *
+     *   if Numeric->front_alloc_init < 0:
+     *     allocate a front of size -Numeric->front_alloc_init.
+     *
+     * Allocate the whole thing if it's small (less than 2*nb^2).  Make sure the
+     * leading dimension of the frontal matrix is odd.
+     *
+     * Also allocate the nb-by-nb LU block, the dr-by-nb L block, and the
+     * nb-by-dc U block.
+     * ---------------------------------------------------------------------- */
+
+    /* get the maximum front size, avoiding integer overflow */
+    overflow = INT_OVERFLOW (maxbytes) ;
+    if (overflow)
+    {
+       /* :: int overflow, max front size :: */
+       maxfrsize = Int_MAX / sizeof (Entry) ;
+    }
+    else
+    {
+       maxfrsize = (fnrows_max + nb) * (fncols_max + nb) ;
+    }
+    ASSERT (!INT_OVERFLOW ((double) maxfrsize * sizeof (Entry))) ;
+
+    if (Numeric->front_alloc_init < 0)
+    {
+       /* allocate a front of -Numeric->front_alloc_init entries */
+       fsize = -Numeric->front_alloc_init ;
+       fsize = MAX (1, fsize) ;
+    }
+    else
+    {
+       if (INT_OVERFLOW (Numeric->front_alloc_init * maxbytes))
+       {
+           /* :: int overflow, requested front size :: */
+           fsize = Int_MAX / sizeof (Entry) ;
+       }
+       else
+       {
+           fsize = Numeric->front_alloc_init * maxfrsize ;
+       }
+
+       if (cdeg > 0)
+       {
+           /* diagonal pivoting is in use.  cdeg was computed above */
+           Int fsize2 ;
+
+           /* add the L and U blocks */
+           cdeg += nb ;
+
+           if (INT_OVERFLOW (((double) cdeg * (double) cdeg) * sizeof (Entry)))
+           {
+               /* :: int overflow, symmetric front size :: */
+               fsize2 = Int_MAX / sizeof (Entry) ;
+           }
+           else
+           {
+               fsize2 = MAX (cdeg * cdeg, fcurr_size) ;
+           }
+           fsize = MIN (fsize, fsize2) ;
+       }
+    }
+
+    fsize = MAX (fsize, 2*nb*nb) ;
+
+    /* fsize and maxfrsize are now safe from integer overflow.  They both
+     * include the size of the pivot blocks. */
+    ASSERT (!INT_OVERFLOW ((double) fsize * sizeof (Entry))) ;
+
+    Work->fnrows_new = 0 ;
+    Work->fncols_new = 0 ;
+
+    /* desired size is fnr2-by-fnc2 (includes L and U blocks): */
+    DEBUGm2 (("    fsize "ID"  fcurr_size "ID"\n", fsize, fcurr_size)) ;
+    DEBUGm2 (("    maxfrsize "ID"  fnr_curr "ID" fnc_curr "ID"\n", maxfrsize,
+       Work->fnr_curr, Work->fnc_curr)) ;
+
+    if (fsize >= maxfrsize && !overflow)
+    {
+       /* max working array is small, allocate all of it */
+       fnr2 = fnrows_max + nb ;
+       fnc2 = fncols_max + nb ;
+       fsize = maxfrsize ;
+       DEBUGm1 (("   sufficient for ("ID"+"ID")-by-("ID"+"ID")\n",
+           fnrows_max, nb, fncols_max, nb)) ;
+    }
+    else
+    {
+       /* allocate a smaller working array */
+       if (fnrows_max <= fncols_max)
+       {
+           fnr2 = (Int) sqrt ((double) fsize) ;
+           /* make sure fnr2 is odd */
+           fnr2 = MAX (fnr2, 1) ;
+           if (fnr2 % 2 == 0) fnr2++ ;
+           fnr2 = MIN (fnr2, fnrows_max + nb) ;
+           fnc2 = fsize / fnr2 ;
+       }
+       else
+       {
+           fnc2 = (Int) sqrt ((double) fsize) ;
+           fnc2 = MIN (fnc2, fncols_max + nb) ;
+           fnr2 = fsize / fnc2 ;
+           /* make sure fnr2 is odd */
+           fnr2 = MAX (fnr2, 1) ;
+           if (fnr2 % 2 == 0)
+           {
+               fnr2++ ;
+               fnc2 = fsize / fnr2 ;
+           }
+       }
+       DEBUGm1 (("   smaller "ID"-by-"ID"\n", fnr2, fnc2)) ;
+    }
+    fnr2 = MIN (fnr2, fnrows_max + nb) ;
+    fnc2 = MIN (fnc2, fncols_max + nb) ;
+    ASSERT (fnr2 % 2 == 1) ;
+    ASSERT (fnr2 * fnc2 <= fsize) ;
+
+    fnr2 -= nb ;
+    fnc2 -= nb ;
+    ASSERT (fnr2 >= 0) ;
+    ASSERT (fnc2 >= 0) ;
+
+    if (fsize > fcurr_size)
+    {
+       DEBUGm1 (("   Grow front \n")) ;
+       Work->do_grow = TRUE ;
+       if (!UMF_grow_front (Numeric, fnr2, fnc2, Work, -1))
+       {
+           /* since the minimum front size is 1-by-1, it would be nearly
+            * impossible to run out of memory here. */
+           DEBUGm4 (("out of memory: start front\n")) ;
+           return (FALSE) ;
+       }
+    }
+    else
+    {
+       /* use the existing front */
+       DEBUGm1 (("   existing front ok\n")) ;
+       Work->fnr_curr = fnr2 ;
+       Work->fnc_curr = fnc2 ;
+       Work->Flblock  = Work->Flublock + nb * nb ;
+       Work->Fublock  = Work->Flblock  + nb * fnr2 ;
+       Work->Fcblock  = Work->Fublock  + nb * fnc2 ;
+    }
+    ASSERT (Work->Flblock  == Work->Flublock + Work->nb*Work->nb) ;
+    ASSERT (Work->Fublock  == Work->Flblock  + Work->fnr_curr*Work->nb) ;
+    ASSERT (Work->Fcblock  == Work->Fublock  + Work->nb*Work->fnc_curr) ;
+    return (TRUE) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_start_front.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_start_front.h
new file mode 100644 (file)
index 0000000..5992e73
--- /dev/null
@@ -0,0 +1,14 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_start_front
+(
+    Int chain,
+    NumericType *Numeric,
+    WorkType *Work,
+    SymbolicType *Symbolic
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_store_lu.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_store_lu.c
new file mode 100644 (file)
index 0000000..df0c63e
--- /dev/null
@@ -0,0 +1,1035 @@
+/* ========================================================================== */
+/* === UMF_store_lu ========================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Store the LU factors.  Called by the kernel.
+    Returns TRUE if successful, FALSE if out of memory.
+*/
+
+#include "umf_internal.h"
+#include "umf_mem_alloc_head_block.h"
+#include "umf_mem_free_tail_block.h"
+#include "umf_get_memory.h"
+
+/* ========================================================================== */
+
+#ifdef DROP
+GLOBAL Int UMF_store_lu_drop
+#else
+GLOBAL Int UMF_store_lu
+#endif
+(
+    NumericType *Numeric,
+    WorkType *Work
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int i, k, fnr_curr, fnrows, fncols, row, col, pivrow, pivcol, *Frows,
+       *Fcols, *Lpattern, *Upattern, *Lpos, *Upos, llen, ulen, fnc_curr, fnpiv,
+       uilen, lnz, unz, nb, *Lilen,
+       *Uilen, *Lip, *Uip, *Li, *Ui, pivcol_position, newLchain, newUchain,
+       pivrow_position, p, size, lip, uip, lnzi, lnzx, unzx, lnz2i, lnz2x,
+       unz2i, unz2x, zero_pivot, *Pivrow, *Pivcol, kk,
+       Lnz [MAXNB] ;
+    Entry *D, pivot_value, *Lval, *Uval, *Fl1, *Fl2, *Fu1, *Fu2,
+       *Flublock, *Flblock, *Fublock ;
+
+#ifndef NDEBUG
+    Int *Col_degree, *Row_degree ;
+#endif
+
+#ifdef DROP
+    Int all_lnz, all_unz ;
+    double droptol ;
+    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 (("\n##################################### STORE LU: fnrows "ID
+       " fncols "ID"\n", fnrows, fncols)) ;
+
+    DEBUG2 (("\nFrontal matrix, including all space:\n"
+               "fnr_curr "ID" fnc_curr "ID" nb    "ID"\n"
+               "fnrows   "ID" fncols   "ID" fnpiv "ID"\n",
+               fnr_curr, fnc_curr, nb, fnrows, fncols, fnpiv)) ;
+
+    DEBUG2 (("\nJust the active part:\n")) ;
+    DEBUG7 (("C  block: ")) ;
+    UMF_dump_dense (Work->Fcblock,  fnr_curr, fnrows, fncols) ;
+    DEBUG7 (("L  block: ")) ;
+    UMF_dump_dense (Work->Flblock,  fnr_curr, fnrows, fnpiv);
+    DEBUG7 (("U' block: ")) ;
+    UMF_dump_dense (Work->Fublock,  fnc_curr, fncols, fnpiv) ;
+    DEBUG7 (("LU block: ")) ;
+    UMF_dump_dense (Work->Flublock, nb, fnpiv, fnpiv) ;
+    DEBUG7 (("Current frontal matrix: (prior to store LU)\n")) ;
+    UMF_dump_current_front (Numeric, Work, TRUE) ;
+#endif
+
+    Pivrow = Work->Pivrow ;
+    Pivcol = Work->Pivcol ;
+
+    /* ---------------------------------------------------------------------- */
+    /* store the columns of L */
+    /* ---------------------------------------------------------------------- */
+
+    for (kk = 0 ; kk < fnpiv ; kk++)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* one more pivot row and column is being stored into L and U */
+       /* ------------------------------------------------------------------ */
+
+       k = Work->npiv + kk ;
+
+       /* ------------------------------------------------------------------ */
+       /* find the kth pivot row and pivot column */
+       /* ------------------------------------------------------------------ */
+
+       pivrow = Pivrow [kk] ;
+       pivcol = Pivcol [kk] ;
+
+#ifndef NDEBUG
+       ASSERT (pivrow >= 0 && pivrow < Work->n_row) ;
+       ASSERT (pivcol >= 0 && pivcol < Work->n_col) ;
+
+       DEBUGm4 ((
+       "\n -------------------------------------------------------------"
+       "Store LU: step " ID"\n", k))  ;
+       ASSERT (k < MIN (Work->n_row, Work->n_col)) ;
+       DEBUG2 (("Store column of L, k = "ID", llen "ID"\n", k, llen)) ;
+       for (i = 0 ; i < llen ; i++)
+       {
+           row = Lpattern [i] ;
+           ASSERT (row >= 0 && row < Work->n_row) ;
+           DEBUG2 (("    Lpattern["ID"] "ID" Lpos "ID, i, row, Lpos [row])) ;
+           if (row == pivrow) DEBUG2 ((" <- pivot row")) ;
+           DEBUG2 (("\n")) ;
+           ASSERT (i == Lpos [row]) ;
+       }
+#endif
+
+       /* ------------------------------------------------------------------ */
+       /* remove pivot row from L */
+       /* ------------------------------------------------------------------ */
+
+       /* remove pivot row index from current column of L */
+       /* if a new Lchain starts, then all entries are removed later */
+       DEBUG2 (("Removing pivrow from Lpattern, k = "ID"\n", k)) ;
+       ASSERT (!NON_PIVOTAL_ROW (pivrow)) ;
+       pivrow_position = Lpos [pivrow] ;
+       if (pivrow_position != EMPTY)
+       {
+           /* place the last entry in the column in the */
+           /* position of the pivot row index */
+           ASSERT (pivrow == Lpattern [pivrow_position]) ;
+           row = Lpattern [--llen] ;
+           /* ASSERT (NON_PIVOTAL_ROW (row)) ; */
+           Lpattern [pivrow_position] = row ;
+           Lpos [row] = pivrow_position ;
+           Lpos [pivrow] = EMPTY ;
+       }
+
+       /* ------------------------------------------------------------------ */
+       /* store the pivot value, for the diagonal matrix D */
+       /* ------------------------------------------------------------------ */
+
+       /* kk-th column of LU block */
+       Fl1 = Flublock + kk * nb ;
+
+       /* kk-th column of L in the L block */
+       Fl2 = Flblock + kk * fnr_curr ;
+
+       /* kk-th pivot in frontal matrix located in Flublock [kk, kk] */
+       pivot_value = Fl1 [kk] ;
+
+       D [k] = pivot_value ;
+       zero_pivot = IS_ZERO (pivot_value) ;
+
+       DEBUG4 (("Pivot D["ID"]=", k)) ;
+       EDEBUG4 (pivot_value) ;
+       DEBUG4 (("\n")) ;
+
+       /* ------------------------------------------------------------------ */
+       /* count nonzeros in kth column of L */
+       /* ------------------------------------------------------------------ */
+
+       lnz = 0 ;
+       lnz2i = 0 ;
+       lnz2x = llen ;
+
+#ifdef DROP
+           all_lnz = 0 ;
+
+           for (i = kk + 1 ; i < fnpiv ; i++)
+           {
+               double s ;
+               Entry 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++)
+           {
+               double s ;
+               Entry 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++)
+               {
+                   double s ;
+                   Int row2, pos ;
+                   Entry 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++)
+               {
+                   double s ;
+                   Int row2, pos ;
+                   Entry 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++)
+               {
+                   Int row2, pos ;
+                   Entry x = Fl1 [i] ;
+                   if (IS_ZERO (x)) continue ;
+                   row2 = Pivrow [i] ;
+                   pos = llen++ ;
+                   Lpattern [pos] = row2 ;
+                   Lpos [row2] = pos ;
+                   Li [pos] = row2 ;
+                   Lval [pos] = x ;
+               }
+
+               for (i = 0 ; i < fnrows ; i++)
+               {
+                   Int row2, pos ;
+                   Entry x = Fl2 [i] ;
+                   if (IS_ZERO (x)) continue ;
+                   row2 = Frows [i] ;
+                   pos = llen++ ;
+                   Lpattern [pos] = row2 ;
+                   Lpos [row2] = pos ;
+                   Li [pos] = row2 ;
+                   Lval [pos] = x ;
+               }
+
+#endif
+
+       }
+       else
+       {
+           ASSERT (llen > 0) ;
+
+#ifdef DROP
+
+               for (i = kk + 1 ; i < fnpiv ; i++)
+               {
+                   double s ;
+                   Int row2, pos ;
+                   Entry 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++)
+               {
+                   double s ;
+                   Int row2, pos ;
+                   Entry 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++)
+               {
+                   Int row2, pos ;
+                   Entry x = Fl1 [i] ;
+                   if (IS_ZERO (x)) continue ;
+                   row2 = Pivrow [i] ;
+                   pos = Lpos [row2] ;
+                   if (pos == EMPTY)
+                   {
+                       pos = llen++ ;
+                       Lpattern [pos] = row2 ;
+                       Lpos [row2] = pos ;
+                       *Li++ = row2 ;
+                   }
+                   Lval [pos] = x ;
+               }
+
+               for (i = 0 ; i < fnrows ; i++)
+               {
+                   Int row2, pos ;
+                   Entry x = Fl2 [i] ;
+                   if (IS_ZERO (x)) continue ;
+                   row2 = Frows [i] ;
+                   pos = Lpos [row2] ;
+                   if (pos == EMPTY)
+                   {
+                       pos = llen++ ;
+                       Lpattern [pos] = row2 ;
+                       Lpos [row2] = pos ;
+                       *Li++ = row2 ;
+                   }
+                   Lval [pos] = x ;
+               }
+
+#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++)
+           {
+               double s ;
+               Entry 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++)
+           {
+               double s ;
+               Entry 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++)
+               {
+                   double s ;
+                   Int col2, pos ;
+                   Entry 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++)
+               {
+                   double s ;
+                   Int col2, pos ;
+                   Entry 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++)
+               {
+                   Int col2, pos ;
+                   Entry x = Fu1 [i*nb] ;
+                   if (IS_ZERO (x)) continue ;
+                   col2 = Pivcol [i] ;
+                   pos = ulen++ ;
+                   Upattern [pos] = col2 ;
+                   Upos [col2] = pos ;
+                   Uval [pos] = x ;
+               }
+
+               for (i = 0 ; i < fncols ; i++)
+               {
+                   Int col2, pos ;
+                   Entry x = Fu2 [i] ;
+                   if (IS_ZERO (x)) continue ;
+                   col2 = Fcols [i] ;
+                   pos = ulen++ ;
+                   Upattern [pos] = col2 ;
+                   Upos [col2] = pos ;
+                   Uval [pos] = x ;
+               }
+
+#endif
+
+       }
+       else
+       {
+
+           ASSERT (ulen > 0) ;
+
+           /* store the numerical entries and find new nonzeros */
+
+#ifdef DROP
+
+               for (i = kk + 1 ; i < fnpiv ; i++)
+               {
+                   double s ;
+                   Int col2, pos ;
+                   Entry 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++)
+               {
+                   double s ;
+                   Int col2, pos ;
+                   Entry 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++)
+               {
+                   Int col2, pos ;
+                   Entry x = Fu1 [i*nb] ;
+                   if (IS_ZERO (x)) continue ;
+                   col2 = Pivcol [i] ;
+                   pos = Upos [col2] ;
+                   if (pos == EMPTY)
+                   {
+                       pos = ulen++ ;
+                       Upattern [pos] = col2 ;
+                       Upos [col2] = pos ;
+                   }
+                   Uval [pos] = x ;
+               }
+
+               for (i = 0 ; i < fncols ; i++)
+               {
+                   Int col2, pos ;
+                   Entry x = Fu2 [i] ;
+                   if (IS_ZERO (x)) continue ;
+                   col2 = Fcols [i] ;
+                   pos = Upos [col2] ;
+                   if (pos == EMPTY)
+                   {
+                       pos = ulen++ ;
+                       Upattern [pos] = col2 ;
+                       Upos [col2] = pos ;
+                   }
+                   Uval [pos] = x ;
+               }
+
+#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/deal.II/contrib/umfpack/UMFPACK/Source/umf_store_lu.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_store_lu.h
new file mode 100644 (file)
index 0000000..142ee5b
--- /dev/null
@@ -0,0 +1,18 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_store_lu
+(
+    NumericType *Numeric,
+    WorkType *Work
+) ;
+
+GLOBAL Int UMF_store_lu_drop
+(
+    NumericType *Numeric,
+    WorkType *Work
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_symbolic_usage.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_symbolic_usage.c
new file mode 100644 (file)
index 0000000..cc8b94a
--- /dev/null
@@ -0,0 +1,46 @@
+/* ========================================================================== */
+/* === UMF_symbolic_usage =================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* Returns the final size of the Symbolic object, in Units */
+
+#include "umf_internal.h"
+
+GLOBAL double UMF_symbolic_usage
+(
+    Int n_row,
+    Int n_col,
+    Int nchains,
+    Int nfr,
+    Int esize,     /* zero if no dense rows.  Otherwise, equal to the
+                    * number of non-singleton, non-empty columns */
+    Int prefer_diagonal
+)
+{
+    double units ;
+
+    units =
+       DUNITS (SymbolicType, 1)        /* Symbolic structure */
+       + 2 * DUNITS (Int, n_col+1)     /* Cperm_init, Cdeg */
+       + 2 * DUNITS (Int, n_row+1)     /* Rperm_init, Rdeg */
+       + 3 * DUNITS (Int, nchains+1)   /* Chain_ */
+       + 4 * DUNITS (Int, nfr+1) ;     /* Front_ */
+
+    /* if dense rows are present */
+    units += DUNITS (Int, esize) ;     /* Esize */
+
+    /* for diagonal pivoting */
+    if (prefer_diagonal)
+    {
+       units += DUNITS (Int, n_col+1) ;    /* Diagonal_map */
+    }
+
+    return (units) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_symbolic_usage.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_symbolic_usage.h
new file mode 100644 (file)
index 0000000..1767c2c
--- /dev/null
@@ -0,0 +1,16 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL double UMF_symbolic_usage
+(
+    Int n_row,
+    Int n_col,
+    Int nchains,
+    Int nfr,
+    Int esize,
+    Int prefer_diagonal
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_transpose.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_transpose.c
new file mode 100644 (file)
index 0000000..0749119
--- /dev/null
@@ -0,0 +1,332 @@
+/* ========================================================================== */
+/* === UMF_transpose ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*  Not user-callable.  Computes a permuted transpose, R = (A (P,Q(1:nq)))' in
+       MATLAB notation, where R is in column-form.  A is n_row-by-n_col, the
+       row-form matrix R is n_row-by-nq, where nq <= n_col.  A may be singular.
+       The complex version can do transpose (') or array transpose (.').
+
+       Uses Gustavson's method (Two Fast Algorithms for Sparse Matrices:
+       Multiplication and Permuted Transposition, ACM Trans. on Math. Softw.,
+       vol 4, no 3, pp. 250-269).
+*/
+
+#include "umf_internal.h"
+#include "umf_is_permutation.h"
+
+GLOBAL Int UMF_transpose
+(
+    Int n_row,                 /* A is n_row-by-n_col */
+    Int n_col,
+    const Int Ap [ ],          /* size n_col+1 */
+    const Int Ai [ ],          /* size nz = Ap [n_col] */
+    const double Ax [ ],       /* size nz if present */
+
+    const Int P [ ],   /* P [k] = i means original row i is kth row in A(P,Q)*/
+                       /* P is identity if not present */
+                       /* size n_row, if present */
+
+    const Int Q [ ],   /* Q [k] = j means original col j is kth col in A(P,Q)*/
+                       /* Q is identity if not present */
+                       /* size nq, if present */
+    Int nq,            /* size of Q, ignored if Q is (Int *) NULL */
+
+                       /* output matrix: Rp, Ri, Rx, and Rz: */
+    Int Rp [ ],                /* size n_row+1 */
+    Int Ri [ ],                /* size nz */
+    double Rx [ ],     /* size nz, if present */
+
+    Int W [ ],         /* size max (n_row,n_col) workspace */
+
+    Int check          /* if true, then check inputs */
+#ifdef COMPLEX
+    , const double Az [ ]      /* size nz */
+    , double Rz [ ]            /* size nz */
+    , Int do_conjugate         /* if true, then do conjugate transpose */
+                               /* otherwise, do array transpose */
+#endif
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int i, j, k, p, bp, newj, do_values ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    Int nz ;
+    ASSERT (n_col >= 0) ;
+    nz = (Ap != (Int *) NULL) ? Ap [n_col] : 0 ;
+    DEBUG2 (("UMF_transpose: "ID"-by-"ID" nz "ID"\n", n_row, n_col, nz)) ;
+#endif
+
+    if (check)
+    {
+       /* UMFPACK_symbolic skips this check */
+       /* UMFPACK_transpose always does this check */
+       if (!Ai || !Ap || !Ri || !Rp || !W)
+       {
+           return (UMFPACK_ERROR_argument_missing) ;
+       }
+       if (n_row <= 0 || n_col <= 0)           /* n_row,n_col must be > 0 */
+       {
+           return (UMFPACK_ERROR_n_nonpositive) ;
+       }
+       if (!UMF_is_permutation (P, W, n_row, n_row) ||
+           !UMF_is_permutation (Q, W, nq, nq))
+       {
+           return (UMFPACK_ERROR_invalid_permutation) ;
+       }
+       if (!AMD_valid (n_row, n_col, Ap, Ai))
+       {
+           return (UMFPACK_ERROR_invalid_matrix) ;
+       }
+    }
+
+#ifndef NDEBUG
+    DEBUG2 (("UMF_transpose, input matrix:\n")) ;
+    UMF_dump_col_matrix (Ax,
+#ifdef COMPLEX
+       Az,
+#endif
+       Ai, Ap, n_row, n_col, nz) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* count the entries in each row of A */
+    /* ---------------------------------------------------------------------- */
+
+    /* use W as workspace for RowCount */
+
+    for (i = 0 ; i < n_row ; i++)
+    {
+       W [i] = 0 ;
+       Rp [i] = 0 ;
+    }
+
+    if (Q != (Int *) NULL)
+    {
+       for (newj = 0 ; newj < nq ; newj++)
+       {
+           j = Q [newj] ;
+           ASSERT (j >= 0 && j < n_col) ;
+           for (p = Ap [j] ; p < Ap [j+1] ; p++)
+           {
+               i = Ai [p] ;
+               ASSERT (i >= 0 && i < n_row) ;
+               W [i]++ ;
+           }
+       }
+    }
+    else
+    {
+       for (j = 0 ; j < n_col ; j++)
+       {
+           for (p = Ap [j] ; p < Ap [j+1] ; p++)
+           {
+               i = Ai [p] ;
+               ASSERT (i >= 0 && i < n_row) ;
+               W [i]++ ;
+           }
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the row pointers for R = A (P,Q) */
+    /* ---------------------------------------------------------------------- */
+
+    if (P != (Int *) NULL)
+    {
+       Rp [0] = 0 ;
+       for (k = 0 ; k < n_row ; k++)
+       {
+           i = P [k] ;
+           ASSERT (i >= 0 && i < n_row) ;
+           Rp [k+1] = Rp [k] + W [i] ;
+       }
+       for (k = 0 ; k < n_row ; k++)
+       {
+           i = P [k] ;
+           ASSERT (i >= 0 && i < n_row) ;
+           W [i] = Rp [k] ;
+       }
+    }
+    else
+    {
+       Rp [0] = 0 ;
+       for (i = 0 ; i < n_row ; i++)
+       {
+           Rp [i+1] = Rp [i] + W [i] ;
+       }
+       for (i = 0 ; i < n_row ; i++)
+       {
+           W [i] = Rp [i] ;
+       }
+    }
+    ASSERT (Rp [n_row] <= Ap [n_col]) ;
+
+    /* at this point, W holds the permuted row pointers */
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the row form of B */
+    /* ---------------------------------------------------------------------- */
+
+    do_values = Ax && Rx ;
+#ifdef COMPLEX
+    do_values = do_values && Az && Rz ;
+#endif
+
+#ifdef COMPLEX
+    if (do_conjugate && do_values)
+    {
+       if (Q != (Int *) NULL)
+       {
+
+               /* R = A (P,Q)' */
+               for (newj = 0 ; newj < nq ; newj++)
+               {
+                   j = Q [newj] ;
+                   ASSERT (j >= 0 && j < n_col) ;
+                   for (p = Ap [j] ; p < Ap [j+1] ; p++)
+                   {
+                       bp = W [Ai [p]]++ ;
+                       Ri [bp] = newj ;
+                       Rx [bp] = Ax [p] ;
+                       Rz [bp] = -Az [p] ;
+                   }
+               }
+
+       }
+       else
+       {
+
+               /* R = A (P,:)' */
+               for (j = 0 ; j < n_col ; j++)
+               {
+                   for (p = Ap [j] ; p < Ap [j+1] ; p++)
+                   {
+                       bp = W [Ai [p]]++ ;
+                       Ri [bp] = j ;
+                       Rx [bp] = Ax [p] ;
+                       Rz [bp] = -Az [p] ;
+                   }
+               }
+
+       }
+    }
+    else
+#endif
+    {
+       if (Q != (Int *) NULL)
+       {
+           if (do_values)
+           {
+
+               /* R = A (P,Q).' */
+               for (newj = 0 ; newj < nq ; newj++)
+               {
+                   j = Q [newj] ;
+                   ASSERT (j >= 0 && j < n_col) ;
+                   for (p = Ap [j] ; p < Ap [j+1] ; p++)
+                   {
+                       bp = W [Ai [p]]++ ;
+                       Ri [bp] = newj ;
+                       Rx [bp] = Ax [p] ;
+#ifdef COMPLEX
+                       Rz [bp] = Az [p] ;
+#endif
+                   }
+               }
+
+           }
+           else
+           {
+
+               /* R = pattern of A (P,Q).' */
+               for (newj = 0 ; newj < nq ; newj++)
+               {
+                   j = Q [newj] ;
+                   ASSERT (j >= 0 && j < n_col) ;
+                   for (p = Ap [j] ; p < Ap [j+1] ; p++)
+                   {
+                       Ri [W [Ai [p]]++] = newj ;
+                   }
+               }
+
+           }
+       }
+       else
+       {
+           if (do_values)
+           {
+
+               /* R = A (P,:).' */
+               for (j = 0 ; j < n_col ; j++)
+               {
+                   for (p = Ap [j] ; p < Ap [j+1] ; p++)
+                   {
+                       bp = W [Ai [p]]++ ;
+                       Ri [bp] = j ;
+                       Rx [bp] = Ax [p] ;
+#ifdef COMPLEX
+                       Rz [bp] = Az [p] ;
+#endif
+                   }
+               }
+
+           }
+           else
+           {
+
+               /* R = pattern of A (P,:).' */
+               for (j = 0 ; j < n_col ; j++)
+               {
+                   for (p = Ap [j] ; p < Ap [j+1] ; p++)
+                   {
+                       Ri [W [Ai [p]]++] = j ;
+                   }
+               }
+
+           }
+       }
+
+    }
+
+#ifndef NDEBUG
+    for (k = 0 ; k < n_row ; k++)
+    {
+       if (P != (Int *) NULL)
+       {
+           i = P [k] ;
+       }
+       else
+       {
+           i = k ;
+       }
+       DEBUG3 ((ID":  W[i] "ID" Rp[k+1] "ID"\n", i, W [i], Rp [k+1])) ;
+       ASSERT (W [i] == Rp [k+1]) ;
+    }
+    DEBUG2 (("UMF_transpose, output matrix:\n")) ;
+    UMF_dump_col_matrix (Rx,
+#ifdef COMPLEX
+       Rz,
+#endif
+       Ri, Rp, n_col, n_row, Rp [n_row]) ;
+    ASSERT (AMD_valid (n_col, n_row, Rp, Ri)) ;
+#endif
+
+    return (UMFPACK_OK) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_transpose.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_transpose.h
new file mode 100644 (file)
index 0000000..0e1aac9
--- /dev/null
@@ -0,0 +1,28 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_transpose
+(
+    Int n_row,
+    Int n_col,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const double Ax [ ],
+    const Int P [ ],
+    const Int Q [ ],
+    Int nq,
+    Int Rp [ ],
+    Int Ri [ ],
+    double Rx [ ],
+    Int W [ ],
+    Int check
+#ifdef COMPLEX
+    , const double Az [ ]
+    , double Rz [ ]
+    , Int do_conjugate
+#endif
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_triplet.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_triplet.c
new file mode 100644 (file)
index 0000000..8192af7
--- /dev/null
@@ -0,0 +1,386 @@
+/* ========================================================================== */
+/* === UMF_triplet ========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Not user callable.  Converts triplet input to column-oriented form.
+    Duplicate entries may exist (they are summed in the output).  The columns
+    of the column-oriented form are in sorted order.  The input is not modified.
+    Returns 1 if OK, 0 if an error occured.
+
+    Compiled into four different routines for each version (di, dl, zi, zl),
+    for a total of 16 different routines.
+*/
+
+#include "umf_internal.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+
+#ifdef DO_MAP
+#ifdef DO_VALUES
+GLOBAL Int UMF_triplet_map_x
+#else
+GLOBAL Int UMF_triplet_map_nox
+#endif
+#else
+#ifdef DO_VALUES
+GLOBAL Int UMF_triplet_nomap_x
+#else
+GLOBAL Int UMF_triplet_nomap_nox
+#endif
+#endif
+(
+    Int n_row,
+    Int n_col,
+    Int nz,
+    const Int Ti [ ],          /* size nz */
+    const Int Tj [ ],          /* size nz */
+    Int Ap [ ],                        /* size n_col + 1 */
+    Int Ai [ ],                        /* size nz */
+    Int Rp [ ],                        /* size n_row + 1 */
+    Int Rj [ ],                        /* size nz */
+    Int W [ ],                 /* size max (n_row, n_col) */
+    Int RowCount [ ]           /* size n_row */
+#ifdef DO_VALUES
+    , const double Tx [ ]      /* size nz */
+    , double Ax [ ]            /* size nz */
+    , double Rx [ ]            /* size nz */
+#ifdef COMPLEX
+    , const double Tz [ ]      /* size nz */
+    , double Az [ ]            /* size nz */
+    , double Rz [ ]            /* size nz */
+#endif
+#endif
+#ifdef DO_MAP
+    , Int Map [ ]              /* size nz */
+    , Int Map2 [ ]             /* size nz */
+#endif
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int i, j, k, p, cp, p1, p2, pdest, pj ;
+#ifdef DO_MAP
+    Int duplicates ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* count the entries in each row (also counting duplicates) */
+    /* ---------------------------------------------------------------------- */
+
+    /* use W as workspace for row counts (including duplicates) */
+    for (i = 0 ; i < n_row ; i++)
+    {
+       W [i] = 0 ;
+    }
+
+    for (k = 0 ; k < nz ; k++)
+    {
+       i = Ti [k] ;
+       j = Tj [k] ;
+       if (i < 0 || i >= n_row || j < 0 || j >= n_col)
+       {
+           return (UMFPACK_ERROR_invalid_matrix) ;
+       }
+       W [i]++ ;
+#ifndef NDEBUG
+       DEBUG1 ((ID " triplet: "ID" "ID" ", k, i, j)) ;
+#ifdef DO_VALUES
+       {
+           Entry tt ;
+           ASSIGN (tt, Tx [k], Tz [k]) ;
+           EDEBUG2 (tt) ;
+           DEBUG1 (("\n")) ;
+       }
+#endif
+#endif
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the row pointers */
+    /* ---------------------------------------------------------------------- */
+
+    Rp [0] = 0 ;
+    for (i = 0 ; i < n_row ; i++)
+    {
+       Rp [i+1] = Rp [i] + W [i] ;
+       W [i] = Rp [i] ;
+    }
+
+    /* W is now equal to the row pointers */
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the row form */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = 0 ; k < nz ; k++)
+    {
+       p = W [Ti [k]]++ ;
+#ifdef DO_MAP
+       Map [k] = p ;
+#endif
+       Rj [p] = Tj [k] ;
+#ifdef DO_VALUES
+       Rx [p] = Tx [k] ;
+#ifdef COMPLEX
+       Rz [p] = Tz [k] ;
+#endif
+#endif
+    }
+
+    /* Rp stays the same, but W [i] is advanced to the start of row i+1 */
+
+#ifndef NDEBUG
+    for (i = 0 ; i < n_row ; i++)
+    {
+       ASSERT (W [i] == Rp [i+1]) ;
+    }
+#ifdef DO_MAP
+    for (k = 0 ; k < nz ; k++)
+    {
+       /* make sure that kth triplet is mapped correctly */
+       p = Map [k] ;
+       DEBUG1 (("First row map: Map ["ID"] = "ID"\n", k, p)) ;
+       i = Ti [k] ;
+       j = Tj [k] ;
+       ASSERT (j == Rj [p]) ;
+       ASSERT (Rp [i] <= p && p < Rp [i+1]) ;
+    }
+#endif
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* sum up duplicates */
+    /* ---------------------------------------------------------------------- */
+
+    /* use W [j] to hold position in Ri/Rx/Rz of a_ij, for row i [ */
+
+    for (j = 0 ; j < n_col ; j++)
+    {
+       W [j] = EMPTY ;
+    }
+
+#ifdef DO_MAP
+    duplicates = FALSE ;
+#endif
+
+    for (i = 0 ; i < n_row ; i++)
+    {
+       p1 = Rp [i] ;
+       p2 = Rp [i+1] ;
+       pdest = p1 ;
+       /* At this point, W [j] < p1 holds true for all columns j, */
+       /* because Ri/Rx/Rz is stored in row oriented order. */
+#ifndef NDEBUG
+       if (UMF_debug >= -2)
+       {
+           for (j = 0 ; j < n_col ; j++)
+           {
+               ASSERT (W [j] < p1) ;
+           }
+       }
+#endif
+       for (p = p1 ; p < p2 ; p++)
+       {
+           j = Rj [p] ;
+           ASSERT (j >= 0 && j < n_col) ;
+           pj = W [j] ;
+           if (pj >= p1)
+           {
+               /* this column index, j, is already in row i, at position pj */
+               ASSERT (pj < p) ;
+               ASSERT (Rj [pj] == j) ;
+#ifdef DO_MAP
+               Map2 [p] = pj ;
+               duplicates = TRUE ;
+#endif
+#ifdef DO_VALUES
+               /* sum the entry */
+               Rx [pj] += Rx [p] ;
+#ifdef COMPLEX
+               Rz [pj] += Rz [p] ;
+#endif
+#endif
+           }
+           else
+           {
+               /* keep the entry */
+               /* also keep track in W[j] of position of a_ij for case above */
+               W [j] = pdest ;
+#ifdef DO_MAP
+               Map2 [p] = pdest ;
+#endif
+               /* no need to move the entry if pdest is equal to p */
+               if (pdest != p)
+               {
+                   Rj [pdest] = j ;
+#ifdef DO_VALUES
+                   Rx [pdest] = Rx [p] ;
+#ifdef COMPLEX
+                   Rz [pdest] = Rz [p] ;
+#endif
+#endif
+               }
+               pdest++ ;
+           }
+       }
+       RowCount [i] = pdest - p1 ;
+    }
+
+    /* done using W for position of a_ij ] */
+
+    /* ---------------------------------------------------------------------- */
+    /* merge Map and Map2 into a single Map */
+    /* ---------------------------------------------------------------------- */
+
+#ifdef DO_MAP
+    if (duplicates)
+    {
+       for (k = 0 ; k < nz ; k++)
+       {
+           Map [k] = Map2 [Map [k]] ;
+       }
+    }
+#ifndef NDEBUG
+    else
+    {
+       /* no duplicates, so no need to recompute Map */
+       for (k = 0 ; k < nz ; k++)
+       {
+           ASSERT (Map2 [k] == k) ;
+       }
+    }
+    for (k = 0 ; k < nz ; k++)
+    {
+       /* make sure that kth triplet is mapped correctly */
+       p = Map [k] ;
+       DEBUG1 (("Second row map: Map ["ID"] = "ID"\n", k, p)) ;
+       i = Ti [k] ;
+       j = Tj [k] ;
+       ASSERT (j == Rj [p]) ;
+       ASSERT (Rp [i] <= p && p < Rp [i+1]) ;
+    }
+#endif
+#endif
+
+    /* now the kth triplet maps to p = Map [k], and thus to Rj/Rx [p] */
+
+    /* ---------------------------------------------------------------------- */
+    /* count the entries in each column */
+    /* ---------------------------------------------------------------------- */
+
+    /* [ use W as work space for column counts of A */
+    for (j = 0 ; j < n_col ; j++)
+    {
+       W [j] = 0 ;
+    }
+
+    for (i = 0 ; i < n_row ; i++)
+    {
+       for (p = Rp [i] ; p < Rp [i] + RowCount [i] ; p++)
+       {
+           j = Rj [p] ;
+           ASSERT (j >= 0 && j < n_col) ;
+           W [j]++ ;
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* create the column pointers */
+    /* ---------------------------------------------------------------------- */
+
+    Ap [0] = 0 ;
+    for (j = 0 ; j < n_col ; j++)
+    {
+       Ap [j+1] = Ap [j] + W [j] ;
+    }
+    /* done using W as workspace for column counts of A ] */
+
+    for (j = 0 ; j < n_col ; j++)
+    {
+       W [j] = Ap [j] ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the column form */
+    /* ---------------------------------------------------------------------- */
+
+    for (i = 0 ; i < n_row ; i++)
+    {
+       for (p = Rp [i] ; p < Rp [i] + RowCount [i] ; p++)
+       {
+           cp = W [Rj [p]]++ ;
+#ifdef DO_MAP
+           Map2 [p] = cp ;
+#endif
+           Ai [cp] = i ;
+#ifdef DO_VALUES
+           Ax [cp] = Rx [p] ;
+#ifdef COMPLEX
+           Az [cp] = Rz [p] ;
+#endif
+#endif
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* merge Map and Map2 into a single Map */
+    /* ---------------------------------------------------------------------- */
+
+#ifdef DO_MAP
+    for (k = 0 ; k < nz ; k++)
+    {
+       Map [k] = Map2 [Map [k]] ;
+    }
+#endif
+
+    /* now the kth triplet maps to p = Map [k], and thus to Ai/Ax [p] */
+
+#ifndef NDEBUG
+    for (j = 0 ; j < n_col ; j++)
+    {
+       ASSERT (W [j] == Ap [j+1]) ;
+    }
+
+    UMF_dump_col_matrix (
+#ifdef DO_VALUES
+       Ax,
+#ifdef COMPLEX
+       Az,
+#endif
+#else
+       (double *) NULL,
+#ifdef COMPLEX
+       (double *) NULL,
+#endif
+#endif
+       Ai, Ap, n_row, n_col, nz) ;
+
+#ifdef DO_MAP
+    for (k = 0 ; k < nz ; k++)
+    {
+       /* make sure that kth triplet is mapped correctly */
+       p = Map [k] ;
+       DEBUG1 (("Col map: Map ["ID"] = "ID"\t", k, p)) ;
+       i = Ti [k] ;
+       j = Tj [k] ;
+       ASSERT (i == Ai [p]) ;
+       DEBUG1 (("   i "ID" j "ID" Ap[j] "ID" p "ID" Ap[j+1] "ID"\n",
+               i, j, Ap [j], p, Ap [j+1])) ;
+       ASSERT (Ap [j] <= p && p < Ap [j+1]) ;
+    }
+#endif
+#endif
+
+    return (UMFPACK_OK) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_triplet.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_triplet.h
new file mode 100644 (file)
index 0000000..73704e6
--- /dev/null
@@ -0,0 +1,86 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_triplet_map_x
+(
+    Int n_row,
+    Int n_col,
+    Int nz,
+    const Int Ti [ ],
+    const Int Tj [ ],
+    Int Ap [ ],
+    Int Ai [ ],
+    Int Rp [ ],
+    Int Rj [ ],
+    Int W [ ],
+    Int RowCount [ ]
+    , const double Tx [ ]
+    , double Ax [ ]
+    , double Rx [ ]
+#ifdef COMPLEX
+    , const double Tz [ ]
+    , double Az [ ]
+    , double Rz [ ]
+#endif
+    , Int Map [ ]
+    , Int Map2 [ ]
+) ;
+
+GLOBAL Int UMF_triplet_map_nox
+(
+    Int n_row,
+    Int n_col,
+    Int nz,
+    const Int Ti [ ],
+    const Int Tj [ ],
+    Int Ap [ ],
+    Int Ai [ ],
+    Int Rp [ ],
+    Int Rj [ ],
+    Int W [ ],
+    Int RowCount [ ]
+    , Int Map [ ]
+    , Int Map2 [ ]
+) ;
+
+GLOBAL Int UMF_triplet_nomap_x
+(
+    Int n_row,
+    Int n_col,
+    Int nz,
+    const Int Ti [ ],
+    const Int Tj [ ],
+    Int Ap [ ],
+    Int Ai [ ],
+    Int Rp [ ],
+    Int Rj [ ],
+    Int W [ ],
+    Int RowCount [ ]
+    , const double Tx [ ]
+    , double Ax [ ]
+    , double Rx [ ]
+#ifdef COMPLEX
+    , const double Tz [ ]
+    , double Az [ ]
+    , double Rz [ ]
+#endif
+) ;
+
+GLOBAL Int UMF_triplet_nomap_nox
+(
+    Int n_row,
+    Int n_col,
+    Int nz,
+    const Int Ti [ ],
+    const Int Tj [ ],
+    Int Ap [ ],
+    Int Ai [ ],
+    Int Rp [ ],
+    Int Rj [ ],
+    Int W [ ],
+    Int RowCount [ ]
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_tuple_lengths.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_tuple_lengths.c
new file mode 100644 (file)
index 0000000..6843428
--- /dev/null
@@ -0,0 +1,136 @@
+/* ========================================================================== */
+/* === UMF_tuple_lengths ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* Determine the tuple list lengths, and the amount of memory required for */
+/* them.  Return the amount of memory needed to store all the tuples. */
+/* This routine assumes that the tuple lists themselves are either already */
+/* deallocated, or will be shortly (so Row[ ].tlen and Col[ ].tlen are */
+/* overwritten) */
+
+#include "umf_internal.h"
+
+GLOBAL Int UMF_tuple_lengths       /* return memory usage */
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    double *p_dusage               /* output argument */
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int e, nrows, ncols, nel, i, *Rows, *Cols, row, col, n_row, n_col, *E,
+       *Row_degree, *Row_tlen, *Col_degree, *Col_tlen, usage, n1 ;
+    double dusage ;
+    Element *ep ;
+    Unit *p ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    E = Work->E ;
+    Row_degree = Numeric->Rperm ;   /* for NON_PIVOTAL_ROW macro only */
+    Col_degree = Numeric->Cperm ;   /* for NON_PIVOTAL_COL macro only */
+    Row_tlen   = Numeric->Uilen ;
+    Col_tlen   = Numeric->Lilen ;
+    n_row = Work->n_row ;
+    n_col = Work->n_col ;
+    n1 = Work->n1 ;
+    nel = Work->nel ;
+
+    DEBUG3 (("TUPLE_LENGTHS: n_row "ID" n_col "ID" nel "ID"\n",
+       n_row, n_col, nel)) ;
+    ASSERT (nel < Work->elen) ;
+
+    /* tuple list lengths already initialized to zero */
+
+    /* ---------------------------------------------------------------------- */
+    /* scan each element: count tuple list lengths (include element 0) */
+    /* ---------------------------------------------------------------------- */
+
+    for (e = 1 ; e <= nel ; e++)       /* for all elements, in any order */
+    {
+       if (E [e])
+       {
+#ifndef NDEBUG
+           UMF_dump_element (Numeric, Work, e, FALSE) ;
+#endif
+           p = Numeric->Memory + E [e] ;
+           GET_ELEMENT_PATTERN (ep, p, Cols, Rows, ncols) ;
+           nrows = ep->nrows ;
+           for (i = 0 ; i < nrows ; i++)
+           {
+               row = Rows [i] ;
+               ASSERT (row == EMPTY || (row >= n1 && row < n_row)) ;
+               if (row >= n1)
+               {
+                   ASSERT (NON_PIVOTAL_ROW (row)) ;
+                   Row_tlen [row] ++ ;
+               }
+           }
+           for (i = 0 ; i < ncols ; i++)
+           {
+               col = Cols [i] ;
+               ASSERT (col == EMPTY || (col >= n1 && col < n_col)) ;
+               if (col >= n1)
+               {
+                   ASSERT (NON_PIVOTAL_COL (col)) ;
+                   Col_tlen [col] ++ ;
+               }
+           }
+       }
+    }
+
+    /* note: tuple lengths are now modified, but the tuple lists are not */
+    /* updated to reflect that fact. */
+
+    /* ---------------------------------------------------------------------- */
+    /* determine the required memory to hold all the tuple lists */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG0 (("UMF_build_tuples_usage\n")) ;
+
+    usage = 0 ;
+    dusage = 0 ;
+
+    ASSERT (Col_tlen && Col_degree) ;
+
+    for (col = n1 ; col < n_col ; col++)
+    {
+       if (NON_PIVOTAL_COL (col))
+       {
+           usage  += 1 +  UNITS (Tuple, TUPLES (Col_tlen [col])) ;
+           dusage += 1 + DUNITS (Tuple, TUPLES (Col_tlen [col])) ;
+           DEBUG0 ((" col: "ID" tlen "ID" usage so far: "ID"\n",
+                    col, Col_tlen [col], usage)) ;
+       }
+    }
+
+    ASSERT (Row_tlen && Row_degree) ;
+
+    for (row = n1 ; row < n_row ; row++)
+    {
+       if (NON_PIVOTAL_ROW (row))
+       {
+           usage  += 1 +  UNITS (Tuple, TUPLES (Row_tlen [row])) ;
+           dusage += 1 + DUNITS (Tuple, TUPLES (Row_tlen [row])) ;
+           DEBUG0 ((" row: "ID" tlen "ID" usage so far: "ID"\n",
+                    row, Row_tlen [row], usage)) ;
+       }
+    }
+
+    DEBUG0 (("UMF_build_tuples_usage "ID" %g\n", usage, dusage)) ;
+
+    *p_dusage = dusage ;
+    return (usage) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_tuple_lengths.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_tuple_lengths.h
new file mode 100644 (file)
index 0000000..6d1560b
--- /dev/null
@@ -0,0 +1,13 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_tuple_lengths
+(
+    NumericType *Numeric,
+    WorkType *Work,
+    double *dusage
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_usolve.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_usolve.c
new file mode 100644 (file)
index 0000000..c292eb4
--- /dev/null
@@ -0,0 +1,226 @@
+/* ========================================================================== */
+/* === UMF_usolve =========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*  solves Ux = b, where U is the upper triangular factor of a matrix. */
+/*  B is overwritten with the solution X. */
+/*  Returns the floating point operation count */
+
+#include "umf_internal.h"
+
+GLOBAL double UMF_usolve
+(
+    NumericType *Numeric,
+    Entry X [ ],               /* b on input, solution x on output */
+    Int Pattern [ ]            /* a work array of size n */
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int k, deg, j, *ip, col, *Upos, *Uilen, pos,
+       *Uip, n, ulen, up, newUchain, npiv, n1, *Ui ;
+    Entry *xp, xk, *D, *Uval ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    if (Numeric->n_row != Numeric->n_col) return (0.) ;
+    n = Numeric->n_row ;
+    npiv = Numeric->npiv ;
+    Upos = Numeric->Upos ;
+    Uilen = Numeric->Uilen ;
+    Uip = Numeric->Uip ;
+    D = Numeric->D ;
+    n1 = Numeric->n1 ;
+
+#ifndef NDEBUG
+    DEBUG4 (("Usolve start:  npiv = "ID" n = "ID"\n", npiv, n)) ;
+    for (j = 0 ; j < n ; j++)
+    {
+       DEBUG4 (("Usolve start "ID": ", j)) ;
+       EDEBUG4 (X [j]) ;
+       DEBUG4 (("\n")) ;
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* singular case */
+    /* ---------------------------------------------------------------------- */
+
+#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/deal.II/contrib/umfpack/UMFPACK/Source/umf_usolve.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_usolve.h
new file mode 100644 (file)
index 0000000..c546111
--- /dev/null
@@ -0,0 +1,13 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL double UMF_usolve
+(
+    NumericType *Numeric,
+    Entry X [ ],
+    Int Pattern [ ]
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_utsolve.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_utsolve.c
new file mode 100644 (file)
index 0000000..bd7d08e
--- /dev/null
@@ -0,0 +1,331 @@
+/* ========================================================================== */
+/* === UMF_utsolve ========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*  solves U'x = b or U.'x=b, where U is the upper triangular factor of a */
+/*  matrix.  B is overwritten with the solution X. */
+/*  Returns the floating point operation count */
+
+#include "umf_internal.h"
+
+GLOBAL double
+#ifdef CONJUGATE_SOLVE
+UMF_uhsolve                    /* solve U'x=b  (complex conjugate transpose) */
+#else
+UMF_utsolve                    /* solve U.'x=b (array transpose) */
+#endif
+(
+    NumericType *Numeric,
+    Entry X [ ],               /* b on input, solution x on output */
+    Int Pattern [ ]            /* a work array of size n */
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int k, deg, j, *ip, col, *Upos, *Uilen, kstart, kend, up,
+       *Uip, n, uhead, ulen, pos, npiv, n1, *Ui ;
+    Entry *xp, xk, *D, *Uval ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    if (Numeric->n_row != Numeric->n_col) return (0.) ;
+    n = Numeric->n_row ;
+    npiv = Numeric->npiv ;
+    Upos = Numeric->Upos ;
+    Uilen = Numeric->Uilen ;
+    Uip = Numeric->Uip ;
+    D = Numeric->D ;
+    kend = 0 ;
+    n1 = Numeric->n1 ;
+
+#ifndef NDEBUG
+    DEBUG4 (("Utsolve start: npiv "ID" n "ID"\n", npiv, n)) ;
+    for (j = 0 ; j < n ; j++)
+    {
+       DEBUG4 (("Utsolve start "ID": ", j)) ;
+       EDEBUG4 (X [j]) ;
+       DEBUG4 (("\n")) ;
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* singletons */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = 0 ; k < n1 ; k++)
+    {
+       DEBUG4 (("Singleton k "ID"\n", k)) ;
+
+#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/deal.II/contrib/umfpack/UMFPACK/Source/umf_utsolve.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_utsolve.h
new file mode 100644 (file)
index 0000000..86ccb40
--- /dev/null
@@ -0,0 +1,21 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL double UMF_utsolve
+(
+    NumericType *Numeric,
+    Entry X [ ],
+    Int Pattern [ ]
+) ;
+
+
+GLOBAL double UMF_uhsolve
+(
+    NumericType *Numeric,
+    Entry X [ ],
+    Int Pattern [ ]
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_valid_numeric.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_valid_numeric.c
new file mode 100644 (file)
index 0000000..58da8ac
--- /dev/null
@@ -0,0 +1,47 @@
+/* ========================================================================== */
+/* === UMF_valid_numeric ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/* Returns TRUE if the Numeric object is valid, FALSE otherwise. */
+/* Does not check everything.  UMFPACK_report_numeric checks more. */
+
+#include "umf_internal.h"
+
+GLOBAL Int UMF_valid_numeric
+(
+    NumericType *Numeric
+)
+{
+    /* This routine does not check the contents of the individual arrays, so */
+    /* it can miss some errors.  All it checks for is the presence of the */
+    /* arrays, and the Numeric "valid" entry. */
+
+    if (!Numeric)
+    {
+       return (FALSE) ;
+    }
+
+    if (Numeric->valid != NUMERIC_VALID)
+    {
+       /* Numeric does not point to a NumericType object */
+       return (FALSE) ;
+    }
+
+    if (Numeric->n_row <= 0 || Numeric->n_col <= 0 || !Numeric->D ||
+       !Numeric->Rperm || !Numeric->Cperm ||
+       !Numeric->Lpos || !Numeric->Upos ||
+       !Numeric->Lilen || !Numeric->Uilen || !Numeric->Lip || !Numeric->Uip ||
+       !Numeric->Memory || (Numeric->ulen > 0 && !Numeric->Upattern))
+    {
+       return (FALSE) ;
+    }
+
+    return (TRUE) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_valid_numeric.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_valid_numeric.h
new file mode 100644 (file)
index 0000000..11895fd
--- /dev/null
@@ -0,0 +1,11 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_valid_numeric
+(
+    NumericType *Numeric
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_valid_symbolic.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_valid_symbolic.c
new file mode 100644 (file)
index 0000000..1acc6ac
--- /dev/null
@@ -0,0 +1,48 @@
+/* ========================================================================== */
+/* === UMF_valid_symbolic =================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+#include "umf_internal.h"
+
+/* Returns TRUE if the Symbolic object is valid, FALSE otherwise. */
+/* The UMFPACK_report_symbolic routine does a more thorough check. */
+
+GLOBAL Int UMF_valid_symbolic
+(
+    SymbolicType *Symbolic
+)
+{
+    /* This routine does not check the contents of the individual arrays, so */
+    /* it can miss some errors.  All it checks for is the presence of the */
+    /* arrays, and the Symbolic "valid" entry. */
+
+    if (!Symbolic)
+    {
+       return (FALSE) ;
+    }
+
+    if (Symbolic->valid != SYMBOLIC_VALID)
+    {
+       /* Symbolic does not point to a SymbolicType object */
+       return (FALSE) ;
+    }
+
+    if (!Symbolic->Cperm_init || !Symbolic->Rperm_init ||
+       !Symbolic->Front_npivcol || !Symbolic->Front_1strow ||
+       !Symbolic->Front_leftmostdesc ||
+       !Symbolic->Front_parent || !Symbolic->Chain_start ||
+       !Symbolic->Chain_maxrows || !Symbolic->Chain_maxcols ||
+       Symbolic->n_row <= 0 || Symbolic->n_col <= 0)
+    {
+       return (FALSE) ;
+    }
+
+    return (TRUE) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_valid_symbolic.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_valid_symbolic.h
new file mode 100644 (file)
index 0000000..5cada3c
--- /dev/null
@@ -0,0 +1,11 @@
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_valid_symbolic
+(
+    SymbolicType *Symbolic
+) ;
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_version.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_version.h
new file mode 100644 (file)
index 0000000..b3c4df0
--- /dev/null
@@ -0,0 +1,989 @@
+/* ========================================================================== */
+/* === umf_version.h ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+   Define routine names, depending on version being compiled.
+
+   DINT:       double precision, int's as integers
+   DLONG:      double precision, long's as integers
+   ZLONG:      complex double precision, long's as integers
+   ZINT:       complex double precision, int's as integers
+*/
+
+/* Set DINT as the default, if nothing is defined */
+#if !defined (DLONG) && !defined (DINT) && !defined (ZLONG) && !defined (ZINT)
+#define DINT
+#endif
+
+/* Determine if this is a real or complex version */
+#if defined (ZLONG) || defined (ZINT)
+#define COMPLEX
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* integer type (Int is int or long) now defined in amd_internal.h */
+/* -------------------------------------------------------------------------- */
+
+#if defined (DLONG) || defined (ZLONG)
+#define LONG_INTEGER
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* Numerical relop macros for correctly handling the NaN case */
+/* -------------------------------------------------------------------------- */
+
+/*
+SCALAR_IS_NAN(x):
+    True if x is NaN.  False otherwise.  The commonly-existing isnan(x)
+    function could be used, but it's not in Kernighan & Ritchie 2nd edition
+    (ANSI C).  It may appear in <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 (MATHWORKS)
+
+/* The MathWorks has their own macros in util.h that handle NaN's properly. */
+#define SCALAR_IS_NAN(x)       (utIsNaN (x))
+#define SCALAR_IS_ZERO(x)      (utEQZero (x))
+#define SCALAR_IS_NONZERO(x)   (utNEZero (x))
+#define SCALAR_IS_LTZERO(x)    (utLTZero (x))
+
+#elif defined (UMF_WINDOWS)
+
+/* Yes, this is exceedingly ugly.  Blame Microsoft, which hopelessly */
+/* violates the IEEE 754 floating-point standard in a bizarre way. */
+/* If you're using an IEEE 754-compliant compiler, then x != x is true */
+/* iff x is NaN.  For Microsoft, (x < x) is true iff x is NaN. */
+/* So either way, this macro safely detects a NaN. */
+#define SCALAR_IS_NAN(x)       (((x) != (x)) || (((x) < (x))))
+#define SCALAR_IS_ZERO(x)      (((x) == 0.) && !SCALAR_IS_NAN(x))
+#define SCALAR_IS_NONZERO(x)   (((x) != 0.) || SCALAR_IS_NAN(x))
+#define SCALAR_IS_LTZERO(x)    (((x) < 0.) && !SCALAR_IS_NAN(x))
+
+#else
+
+/* These all work properly, according to the IEEE 754 standard ... except on */
+/* a PC with windows.  Works fine in Linux on the same PC... */
+#define SCALAR_IS_NAN(x)       ((x) != (x))
+#define SCALAR_IS_ZERO(x)      ((x) == 0.)
+#define SCALAR_IS_NONZERO(x)   ((x) != 0.)
+#define SCALAR_IS_LTZERO(x)    ((x) < 0.)
+
+#endif
+
+/* scalar absolute value macro. If x is NaN, the result is NaN: */
+#define SCALAR_ABS(x) ((SCALAR_IS_LTZERO (x)) ? -(x) : (x))
+
+/* true if an integer (stored in double x) would overflow (or if x is NaN) */
+#define INT_OVERFLOW(x) ((!((x) * (1.0+1e-8) <= (double) Int_MAX)) \
+                       || SCALAR_IS_NAN (x))
+
+/* print a scalar (avoid printing "-0" for negative zero).  */
+#define PRINT_SCALAR(a) \
+{ \
+    if (SCALAR_IS_NONZERO (a)) \
+    { \
+       PRINTF ((" (%g)", (a))) ; \
+    } \
+    else \
+    { \
+       PRINTF ((" (0)")) ; \
+    } \
+}
+
+/* -------------------------------------------------------------------------- */
+/* Real floating-point arithmetic */
+/* -------------------------------------------------------------------------- */
+
+#ifndef COMPLEX
+
+#define Entry double
+
+#define REAL_COMPONENT(c)              (c)
+#define IMAG_COMPONENT(c)              (0.)
+#define ASSIGN(c,s1,s2)                    { (c) = (s1) ; }
+#define CLEAR(c)                   { (c) = 0. ; }
+#define CLEAR_AND_INCREMENT(p)     { *p++ = 0. ; }
+#define IS_NAN(a)                  SCALAR_IS_NAN (a)
+#define IS_ZERO(a)                 SCALAR_IS_ZERO (a)
+#define IS_NONZERO(a)              SCALAR_IS_NONZERO (a)
+#define SCALE_DIV(c,s)             { (c) /= (s) ; }
+#ifndef NRECIPROCAL
+#define SCALE_RECIP(c,s)           { (c) *= (s) ; }
+#endif
+#define ASSEMBLE(c,a)              { (c) += (a) ; }
+#define ASSEMBLE_AND_INCREMENT(c,p) { (c) += *p++ ; }
+#define DECREMENT(c,a)             { (c) -= (a) ; }
+#define MULT(c,a,b)                { (c) = (a) * (b) ; }
+#define MULT_CONJ(c,a,b)           { (c) = (a) * (b) ; }
+#define MULT_SUB(c,a,b)                    { (c) -= (a) * (b) ; }
+#define MULT_SUB_CONJ(c,a,b)       { (c) -= (a) * (b) ; }
+#define DIV(c,a,b)                 { (c) = (a) / (b) ; }
+#define RECIPROCAL(c)              { (c) = 1.0 / (c) ; }
+#define DIV_CONJ(c,a,b)                    { (c) = (a) / (b) ; }
+#define APPROX_ABS(s,a)                    { (s) = SCALAR_ABS (a) ; }
+#define ABS(s,a)                   { (s) = SCALAR_ABS (a) ; }
+#define PRINT_ENTRY(a)             PRINT_SCALAR (a)
+
+/* for flop counts */
+#define MULTSUB_FLOPS  2.      /* c -= a*b */
+#define DIV_FLOPS      1.      /* c = a/b */
+#define ABS_FLOPS      0.      /* c = abs (a) */
+#define ASSEMBLE_FLOPS 1.      /* c += a */
+#define DECREMENT_FLOPS        1.      /* c -= a */
+#define MULT_FLOPS     1.      /* c = a*b */
+#define SCALE_FLOPS    1.      /* c = a/s */
+
+#else
+
+/* -------------------------------------------------------------------------- */
+/* Complex floating-point arithmetic */
+/* -------------------------------------------------------------------------- */
+
+/*
+    Note:  An alternative to this DoubleComplex type would be to use a
+    struct { double r ; double i ; }.  The problem with that method
+    (used by the Sun Performance Library, for example) is that ANSI C provides
+    no guarantee about the layout of a struct.  It is possible that the sizeof
+    the struct above would be greater than 2 * sizeof (double).  This would
+    mean that the complex BLAS could not be used.  The method used here avoids
+    that possibility.  ANSI C *does* guarantee that an array of structs has
+    the same size as n times the size of one struct.
+
+    The ANSI C99 version of the C language includes a "double _Complex" type.
+    It should be possible in that case to do the following:
+
+    #define Entry double _Complex
+
+    and remove the DoubleComplex struct.  The macros, below, could then be
+    replaced with instrinsic operators.  Note that the #define Real and
+    #define Imag should also be removed (they only appear in this file).
+
+    For the MULT, MULT_SUB, MULT_SUB_CONJ, and MULT_CONJ macros,
+    the output argument c cannot be the same as any input argument.
+
+*/
+
+typedef struct
+{
+    double component [2] ;     /* real and imaginary parts */
+
+} DoubleComplex ;
+
+#define Entry DoubleComplex
+#define Real component [0]
+#define Imag component [1]
+
+/* for flop counts */
+#define MULTSUB_FLOPS  8.      /* c -= a*b */
+#define DIV_FLOPS      9.      /* c = a/b */
+#define ABS_FLOPS      6.      /* c = abs (a), count sqrt as one flop */
+#define ASSEMBLE_FLOPS 2.      /* c += a */
+#define DECREMENT_FLOPS        2.      /* c -= a */
+#define MULT_FLOPS     6.      /* c = a*b */
+#define SCALE_FLOPS    2.      /* c = a/s or c = a*s */
+
+/* -------------------------------------------------------------------------- */
+
+/* real part of c */
+#define REAL_COMPONENT(c) ((c).Real)
+
+/* -------------------------------------------------------------------------- */
+
+/* imag part of c */
+#define IMAG_COMPONENT(c) ((c).Imag)
+
+/* -------------------------------------------------------------------------- */
+
+/* c = (s1) + (s2)i */
+#define ASSIGN(c,s1,s2) \
+{ \
+    (c).Real = (s1) ; \
+    (c).Imag = (s2) ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c = 0 */
+#define CLEAR(c) \
+{ \
+    (c).Real = 0. ; \
+    (c).Imag = 0. ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* *p++ = 0 */
+#define CLEAR_AND_INCREMENT(p) \
+{ \
+    p->Real = 0. ; \
+    p->Imag = 0. ; \
+    p++ ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* True if a == 0 */
+#define IS_ZERO(a) \
+    (SCALAR_IS_ZERO ((a).Real) && SCALAR_IS_ZERO ((a).Imag))
+
+/* -------------------------------------------------------------------------- */
+
+/* True if a is NaN */
+#define IS_NAN(a) \
+    (SCALAR_IS_NAN ((a).Real) || SCALAR_IS_NAN ((a).Imag))
+
+/* -------------------------------------------------------------------------- */
+
+/* True if a != 0 */
+#define IS_NONZERO(a) \
+    (SCALAR_IS_NONZERO ((a).Real) || SCALAR_IS_NONZERO ((a).Imag))
+
+/* -------------------------------------------------------------------------- */
+
+/* c /= s */
+#define SCALE_DIV(c,s) \
+{ \
+    (c).Real /= (s) ; \
+    (c).Imag /= (s) ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c *= s, where s is the reciprocal scale factor.  Not used if
+ * NRECIPROCAL is defined at compile time. */
+#ifndef NRECIPROCAL
+#define SCALE_RECIP(c,s) \
+{ \
+    (c).Real *= (s) ; \
+    (c).Imag *= (s) ; \
+}
+#endif
+
+/* -------------------------------------------------------------------------- */
+
+/* c += a */
+#define ASSEMBLE(c,a) \
+{ \
+    (c).Real += (a).Real ; \
+    (c).Imag += (a).Imag ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c += *p++ */
+#define ASSEMBLE_AND_INCREMENT(c,p) \
+{ \
+    (c).Real += p->Real ; \
+    (c).Imag += p->Imag ; \
+    p++ ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c -= a */
+#define DECREMENT(c,a) \
+{ \
+    (c).Real -= (a).Real ; \
+    (c).Imag -= (a).Imag ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c = a*b, assert because c cannot be the same as a or b */
+#define MULT(c,a,b) \
+{ \
+    ASSERT (&(c) != &(a) && &(c) != &(b)) ; \
+    (c).Real = (a).Real * (b).Real - (a).Imag * (b).Imag ; \
+    (c).Imag = (a).Imag * (b).Real + (a).Real * (b).Imag ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c = a*conjugate(b), assert because c cannot be the same as a or b */
+#define MULT_CONJ(c,a,b) \
+{ \
+    ASSERT (&(c) != &(a) && &(c) != &(b)) ; \
+    (c).Real = (a).Real * (b).Real + (a).Imag * (b).Imag ; \
+    (c).Imag = (a).Imag * (b).Real - (a).Real * (b).Imag ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c -= a*b, assert because c cannot be the same as a or b */
+#define MULT_SUB(c,a,b) \
+{ \
+    ASSERT (&(c) != &(a) && &(c) != &(b)) ; \
+    (c).Real -= (a).Real * (b).Real - (a).Imag * (b).Imag ; \
+    (c).Imag -= (a).Imag * (b).Real + (a).Real * (b).Imag ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c -= a*conjugate(b), assert because c cannot be the same as a or b */
+#define MULT_SUB_CONJ(c,a,b) \
+{ \
+    ASSERT (&(c) != &(a) && &(c) != &(b)) ; \
+    (c).Real -= (a).Real * (b).Real + (a).Imag * (b).Imag ; \
+    (c).Imag -= (a).Imag * (b).Real - (a).Real * (b).Imag ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c = a/b, be careful to avoid underflow and overflow */
+#ifdef MATHWORKS
+#define DIV(c,a,b) \
+{ \
+    (void) utDivideComplex ((a).Real, (a).Imag, (b).Real, (b).Imag, \
+       &((c).Real), &((c).Imag)) ; \
+}
+#else
+/* This uses ACM Algo 116, by R. L. Smith, 1962. */
+/* c can be the same variable as a or b. */
+/* Ignore NaN case for double relop br>=bi. */
+#define DIV(c,a,b) \
+{ \
+    double r, den, ar, ai, br, bi ; \
+    br = (b).Real ; \
+    bi = (b).Imag ; \
+    ar = (a).Real ; \
+    ai = (a).Imag ; \
+    if (SCALAR_ABS (br) >= SCALAR_ABS (bi)) \
+    { \
+       r = bi / br ; \
+       den = br + r * bi ; \
+       (c).Real = (ar + ai * r) / den ; \
+       (c).Imag = (ai - ar * r) / den ; \
+    } \
+    else \
+    { \
+       r = br / bi ; \
+       den = r * br + bi ; \
+       (c).Real = (ar * r + ai) / den ; \
+       (c).Imag = (ai * r - ar) / den ; \
+    } \
+}
+#endif
+
+/* -------------------------------------------------------------------------- */
+
+/* c = 1/c, be careful to avoid underflow and overflow */
+/* Not used if MATHWORKS is defined. */
+/* This uses ACM Algo 116, by R. L. Smith, 1962. */
+/* Ignore NaN case for double relop cr>=ci. */
+#define RECIPROCAL(c) \
+{ \
+    double r, den, cr, ci ; \
+    cr = (c).Real ; \
+    ci = (c).Imag ; \
+    if (SCALAR_ABS (cr) >= SCALAR_ABS (ci)) \
+    { \
+       r = ci / cr ; \
+       den = cr + r * ci ; \
+       (c).Real = 1.0 / den ; \
+       (c).Imag = - r / den ; \
+    } \
+    else \
+    { \
+       r = cr / ci ; \
+       den = r * cr + ci ; \
+       (c).Real = r / den ; \
+       (c).Imag = - 1.0 / den ; \
+    } \
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+/* c = a/conjugate(b), be careful to avoid underflow and overflow */
+#ifdef MATHWORKS
+#define DIV_CONJ(c,a,b) \
+{ \
+    (void) utDivideComplex ((a).Real, (a).Imag, (b).Real, (-(b).Imag), \
+       &((c).Real), &((c).Imag)) ; \
+}
+#else
+/* This uses ACM Algo 116, by R. L. Smith, 1962. */
+/* c can be the same variable as a or b. */
+/* Ignore NaN case for double relop br>=bi. */
+#define DIV_CONJ(c,a,b) \
+{ \
+    double r, den, ar, ai, br, bi ; \
+    br = (b).Real ; \
+    bi = (b).Imag ; \
+    ar = (a).Real ; \
+    ai = (a).Imag ; \
+    if (SCALAR_ABS (br) >= SCALAR_ABS (bi)) \
+    { \
+       r = (-bi) / br ; \
+       den = br - r * bi ; \
+       (c).Real = (ar + ai * r) / den ; \
+       (c).Imag = (ai - ar * r) / den ; \
+    } \
+    else \
+    { \
+       r = br / (-bi) ; \
+       den =  r * br - bi; \
+       (c).Real = (ar * r + ai) / den ; \
+       (c).Imag = (ai * r - ar) / den ; \
+    } \
+}
+#endif
+
+/* -------------------------------------------------------------------------- */
+
+/* approximate absolute value, s = |r|+|i| */
+#define APPROX_ABS(s,a) \
+{ \
+    (s) = SCALAR_ABS ((a).Real) + SCALAR_ABS ((a).Imag) ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* exact absolute value, s = sqrt (a.real^2 + amag^2) */
+#ifdef MATHWORKS
+#define ABS(s,a) \
+{ \
+    (s) = utFdlibm_hypot ((a).Real, (a).Imag) ; \
+}
+#else
+/* Ignore NaN case for the double relops ar>=ai and ar+ai==ar. */
+#define ABS(s,a) \
+{ \
+    double r, ar, ai ; \
+    ar = SCALAR_ABS ((a).Real) ; \
+    ai = SCALAR_ABS ((a).Imag) ; \
+    if (ar >= ai) \
+    { \
+       if (ar + ai == ar) \
+       { \
+           (s) = ar ; \
+       } \
+       else \
+       { \
+           r = ai / ar ; \
+           (s) = ar * sqrt (1.0 + r*r) ; \
+       } \
+    } \
+    else \
+    { \
+       if (ai + ar == ai) \
+       { \
+           (s) = ai ; \
+       } \
+       else \
+       { \
+           r = ar / ai ; \
+           (s) = ai * sqrt (1.0 + r*r) ; \
+       } \
+    } \
+}
+#endif
+
+/* -------------------------------------------------------------------------- */
+
+/* print an entry (avoid printing "-0" for negative zero).  */
+#define PRINT_ENTRY(a) \
+{ \
+    if (SCALAR_IS_NONZERO ((a).Real)) \
+    { \
+       PRINTF ((" (%g", (a).Real)) ; \
+    } \
+    else \
+    { \
+       PRINTF ((" (0")) ; \
+    } \
+    if (SCALAR_IS_LTZERO ((a).Imag)) \
+    { \
+       PRINTF ((" - %gi)", -(a).Imag)) ; \
+    } \
+    else if (SCALAR_IS_ZERO ((a).Imag)) \
+    { \
+       PRINTF ((" + 0i)")) ; \
+    } \
+    else \
+    { \
+       PRINTF ((" + %gi)", (a).Imag)) ; \
+    } \
+}
+
+/* -------------------------------------------------------------------------- */
+
+#endif /* #ifndef COMPLEX */
+
+/* -------------------------------------------------------------------------- */
+/* Double precision, with int's as integers */
+/* -------------------------------------------------------------------------- */
+
+#ifdef DINT
+
+#define UMF_analyze             umf_i_analyze
+#define UMF_apply_order                 umf_i_apply_order
+#define UMF_assemble            umfdi_assemble
+#define UMF_assemble_fixq       umfdi_assemble_fixq
+#define UMF_blas3_update        umfdi_blas3_update
+#define UMF_build_tuples        umfdi_build_tuples
+#define UMF_build_tuples_usage  umfdi_build_tuples_usage
+#define UMF_colamd              umf_i_colamd
+#define UMF_colamd_set_defaults         umf_i_colamd_set_defaults
+#define UMF_create_element      umfdi_create_element
+#define UMF_extend_front        umfdi_extend_front
+#define UMF_free                umf_i_free
+#define UMF_fsize               umf_i_fsize
+#define UMF_garbage_collection  umfdi_garbage_collection
+#define UMF_get_memory          umfdi_get_memory
+#define UMF_grow_front          umfdi_grow_front
+#define UMF_init_front          umfdi_init_front
+#define UMF_is_permutation      umf_i_is_permutation
+#define UMF_kernel              umfdi_kernel
+#define UMF_kernel_init                 umfdi_kernel_init
+#define UMF_kernel_init_usage   umfdi_kernel_init_usage
+#define UMF_kernel_wrapup       umfdi_kernel_wrapup
+#define UMF_local_search        umfdi_local_search
+#define UMF_lsolve              umfdi_lsolve
+#define UMF_ltsolve             umfdi_ltsolve
+#define UMF_lhsolve             umfdi_lhsolve
+#define UMF_malloc              umf_i_malloc
+#define UMF_mem_alloc_element   umfdi_mem_alloc_element
+#define UMF_mem_alloc_head_block umfdi_mem_alloc_head_block
+#define UMF_mem_alloc_tail_block umfdi_mem_alloc_tail_block
+#define UMF_mem_free_tail_block         umfdi_mem_free_tail_block
+#define UMF_mem_init_memoryspace umfdi_mem_init_memoryspace
+#define UMF_realloc             umf_i_realloc
+#define UMF_report_perm                 umf_i_report_perm
+#define UMF_report_vector       umfdi_report_vector
+#define UMF_row_search          umfdi_row_search
+#define UMF_scale               umfdi_scale
+#define UMF_scale_column        umfdi_scale_column
+#define UMF_set_stats           umf_i_set_stats
+#define UMF_singletons          umf_i_singletons
+#define UMF_solve               umfdi_solve
+#define UMF_start_front                 umfdi_start_front
+#define UMF_store_lu            umfdi_store_lu
+#define UMF_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_numeric                 umfpack_di_numeric
+#define UMFPACK_qsymbolic       umfpack_di_qsymbolic
+#define UMFPACK_report_control  umfpack_di_report_control
+#define UMFPACK_report_info     umfpack_di_report_info
+#define UMFPACK_report_matrix   umfpack_di_report_matrix
+#define UMFPACK_report_numeric  umfpack_di_report_numeric
+#define UMFPACK_report_perm     umfpack_di_report_perm
+#define UMFPACK_report_status   umfpack_di_report_status
+#define UMFPACK_report_symbolic         umfpack_di_report_symbolic
+#define UMFPACK_report_triplet  umfpack_di_report_triplet
+#define UMFPACK_report_vector   umfpack_di_report_vector
+#define UMFPACK_save_numeric    umfpack_di_save_numeric
+#define UMFPACK_save_symbolic   umfpack_di_save_symbolic
+#define UMFPACK_load_numeric    umfpack_di_load_numeric
+#define UMFPACK_load_symbolic   umfpack_di_load_symbolic
+#define UMFPACK_scale           umfpack_di_scale
+#define UMFPACK_solve           umfpack_di_solve
+#define UMFPACK_symbolic        umfpack_di_symbolic
+#define UMFPACK_transpose       umfpack_di_transpose
+#define UMFPACK_triplet_to_col  umfpack_di_triplet_to_col
+#define UMFPACK_wsolve          umfpack_di_wsolve
+
+/* for debugging only: */
+#define UMF_malloc_count        umf_i_malloc_count
+#define UMF_debug               umfdi_debug
+#define UMF_allocfail           umfdi_allocfail
+#define UMF_gprob               umfdi_gprob
+#define UMF_dump_dense          umfdi_dump_dense
+#define UMF_dump_element        umfdi_dump_element
+#define UMF_dump_rowcol                 umfdi_dump_rowcol
+#define UMF_dump_matrix                 umfdi_dump_matrix
+#define UMF_dump_current_front  umfdi_dump_current_front
+#define UMF_dump_lu             umfdi_dump_lu
+#define UMF_dump_memory                 umfdi_dump_memory
+#define UMF_dump_packed_memory  umfdi_dump_packed_memory
+#define UMF_dump_col_matrix     umfdi_dump_col_matrix
+#define UMF_dump_chain          umfdi_dump_chain
+#define UMF_dump_start          umfdi_dump_start
+#define UMF_dump_rowmerge       umfdi_dump_rowmerge
+#define UMF_dump_diagonal_map   umfdi_dump_diagonal_map
+
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* Double precision, with long's as integers */
+/* -------------------------------------------------------------------------- */
+
+#ifdef DLONG
+
+#define UMF_analyze             umf_l_analyze
+#define UMF_apply_order                 umf_l_apply_order
+#define UMF_assemble            umfdl_assemble
+#define UMF_assemble_fixq       umfdl_assemble_fixq
+#define UMF_blas3_update        umfdl_blas3_update
+#define UMF_build_tuples        umfdl_build_tuples
+#define UMF_build_tuples_usage  umfdl_build_tuples_usage
+#define UMF_colamd              umf_l_colamd
+#define UMF_colamd_set_defaults         umf_l_colamd_set_defaults
+#define UMF_create_element      umfdl_create_element
+#define UMF_extend_front        umfdl_extend_front
+#define UMF_free                umf_l_free
+#define UMF_fsize               umf_l_fsize
+#define UMF_garbage_collection  umfdl_garbage_collection
+#define UMF_get_memory          umfdl_get_memory
+#define UMF_grow_front          umfdl_grow_front
+#define UMF_init_front          umfdl_init_front
+#define UMF_is_permutation      umf_l_is_permutation
+#define UMF_kernel              umfdl_kernel
+#define UMF_kernel_init                 umfdl_kernel_init
+#define UMF_kernel_init_usage   umfdl_kernel_init_usage
+#define UMF_kernel_wrapup       umfdl_kernel_wrapup
+#define UMF_local_search        umfdl_local_search
+#define UMF_lsolve              umfdl_lsolve
+#define UMF_ltsolve             umfdl_ltsolve
+#define UMF_lhsolve             umfdl_lhsolve
+#define UMF_malloc              umf_l_malloc
+#define UMF_mem_alloc_element   umfdl_mem_alloc_element
+#define UMF_mem_alloc_head_block umfdl_mem_alloc_head_block
+#define UMF_mem_alloc_tail_block umfdl_mem_alloc_tail_block
+#define UMF_mem_free_tail_block         umfdl_mem_free_tail_block
+#define UMF_mem_init_memoryspace umfdl_mem_init_memoryspace
+#define UMF_realloc             umf_l_realloc
+#define UMF_report_perm                 umf_l_report_perm
+#define UMF_report_vector       umfdl_report_vector
+#define UMF_row_search          umfdl_row_search
+#define UMF_scale               umfdl_scale
+#define UMF_scale_column        umfdl_scale_column
+#define UMF_set_stats           umf_l_set_stats
+#define UMF_singletons          umf_l_singletons
+#define UMF_solve               umfdl_solve
+#define UMF_start_front                 umfdl_start_front
+#define UMF_store_lu            umfdl_store_lu
+#define UMF_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_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_numeric                 umfpack_zi_numeric
+#define UMFPACK_qsymbolic       umfpack_zi_qsymbolic
+#define UMFPACK_report_control  umfpack_zi_report_control
+#define UMFPACK_report_info     umfpack_zi_report_info
+#define UMFPACK_report_matrix   umfpack_zi_report_matrix
+#define UMFPACK_report_numeric  umfpack_zi_report_numeric
+#define UMFPACK_report_perm     umfpack_zi_report_perm
+#define UMFPACK_report_status   umfpack_zi_report_status
+#define UMFPACK_report_symbolic         umfpack_zi_report_symbolic
+#define UMFPACK_report_triplet  umfpack_zi_report_triplet
+#define UMFPACK_report_vector   umfpack_zi_report_vector
+#define UMFPACK_save_numeric    umfpack_zi_save_numeric
+#define UMFPACK_save_symbolic   umfpack_zi_save_symbolic
+#define UMFPACK_load_numeric    umfpack_zi_load_numeric
+#define UMFPACK_load_symbolic   umfpack_zi_load_symbolic
+#define UMFPACK_scale           umfpack_zi_scale
+#define UMFPACK_solve           umfpack_zi_solve
+#define UMFPACK_symbolic        umfpack_zi_symbolic
+#define UMFPACK_transpose       umfpack_zi_transpose
+#define UMFPACK_triplet_to_col  umfpack_zi_triplet_to_col
+#define UMFPACK_wsolve          umfpack_zi_wsolve
+
+/* for debugging only: */
+#define UMF_malloc_count        umf_i_malloc_count
+#define UMF_debug               umfzi_debug
+#define UMF_allocfail           umfzi_allocfail
+#define UMF_gprob               umfzi_gprob
+#define UMF_dump_dense          umfzi_dump_dense
+#define UMF_dump_element        umfzi_dump_element
+#define UMF_dump_rowcol                 umfzi_dump_rowcol
+#define UMF_dump_matrix                 umfzi_dump_matrix
+#define UMF_dump_current_front  umfzi_dump_current_front
+#define UMF_dump_lu             umfzi_dump_lu
+#define UMF_dump_memory                 umfzi_dump_memory
+#define UMF_dump_packed_memory  umfzi_dump_packed_memory
+#define UMF_dump_col_matrix     umfzi_dump_col_matrix
+#define UMF_dump_chain          umfzi_dump_chain
+#define UMF_dump_start          umfzi_dump_start
+#define UMF_dump_rowmerge       umfzi_dump_rowmerge
+#define UMF_dump_diagonal_map   umfzi_dump_diagonal_map
+
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* Complex double precision, with long's as integers */
+/* -------------------------------------------------------------------------- */
+
+#ifdef ZLONG
+
+#define UMF_analyze             umf_l_analyze
+#define UMF_apply_order                 umf_l_apply_order
+#define UMF_assemble            umfzl_assemble
+#define UMF_assemble_fixq       umfzl_assemble_fixq
+#define UMF_blas3_update        umfzl_blas3_update
+#define UMF_build_tuples        umfzl_build_tuples
+#define UMF_build_tuples_usage  umfzl_build_tuples_usage
+#define UMF_colamd              umf_l_colamd
+#define UMF_colamd_set_defaults         umf_l_colamd_set_defaults
+#define UMF_create_element      umfzl_create_element
+#define UMF_extend_front        umfzl_extend_front
+#define UMF_free                umf_l_free
+#define UMF_fsize               umf_l_fsize
+#define UMF_garbage_collection  umfzl_garbage_collection
+#define UMF_get_memory          umfzl_get_memory
+#define UMF_grow_front          umfzl_grow_front
+#define UMF_init_front          umfzl_init_front
+#define UMF_is_permutation      umf_l_is_permutation
+#define UMF_kernel              umfzl_kernel
+#define UMF_kernel_init                 umfzl_kernel_init
+#define UMF_kernel_init_usage   umfzl_kernel_init_usage
+#define UMF_kernel_wrapup       umfzl_kernel_wrapup
+#define UMF_local_search        umfzl_local_search
+#define UMF_lsolve              umfzl_lsolve
+#define UMF_ltsolve             umfzl_ltsolve
+#define UMF_lhsolve             umfzl_lhsolve
+#define UMF_malloc              umf_l_malloc
+#define UMF_mem_alloc_element   umfzl_mem_alloc_element
+#define UMF_mem_alloc_head_block umfzl_mem_alloc_head_block
+#define UMF_mem_alloc_tail_block umfzl_mem_alloc_tail_block
+#define UMF_mem_free_tail_block         umfzl_mem_free_tail_block
+#define UMF_mem_init_memoryspace umfzl_mem_init_memoryspace
+#define UMF_realloc             umf_l_realloc
+#define UMF_report_perm                 umf_l_report_perm
+#define UMF_report_vector       umfzl_report_vector
+#define UMF_row_search          umfzl_row_search
+#define UMF_scale               umfzl_scale
+#define UMF_scale_column        umfzl_scale_column
+#define UMF_set_stats           umfzl_set_stats
+#define UMF_singletons          umf_l_singletons
+#define UMF_solve               umfzl_solve
+#define UMF_start_front                 umfzl_start_front
+#define UMF_store_lu            umfzl_store_lu
+#define UMF_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_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/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_col_to_triplet.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_col_to_triplet.c
new file mode 100644 (file)
index 0000000..ef27bc2
--- /dev/null
@@ -0,0 +1,73 @@
+/* ========================================================================== */
+/* === UMFPACK_col_to_triplet =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User callable.  Converts a column-oriented input matrix to triplet form by
+    constructing the column indices Tj from the column pointers Ap.  The matrix
+    may be singular.  See umfpack_col_to_triplet.h for details.
+
+*/
+
+#include "umf_internal.h"
+
+GLOBAL Int UMFPACK_col_to_triplet
+(
+    Int n_col,
+    const Int Ap [ ],
+    Int Tj [ ]
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int nz, j, p, p1, p2, length ;
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the column indices */
+    /* ---------------------------------------------------------------------- */
+
+    if (!Ap || !Tj)
+    {
+       return (UMFPACK_ERROR_argument_missing) ;
+    }
+    if (n_col <= 0)
+    {
+       return (UMFPACK_ERROR_n_nonpositive) ;
+    }
+    if (Ap [0] != 0)
+    {
+       return (UMFPACK_ERROR_invalid_matrix) ;
+    }
+    nz = Ap [n_col] ;
+    if (nz < 0)
+    {
+       return (UMFPACK_ERROR_invalid_matrix) ;
+    }
+
+    for (j = 0 ; j < n_col ; j++)
+    {
+       p1 = Ap [j] ;
+       p2 = Ap [j+1] ;
+       length = p2 - p1 ;
+       if (length < 0 || p2 > nz)
+       {
+           return (UMFPACK_ERROR_invalid_matrix) ;
+       }
+       for (p = p1 ; p < p2 ; p++)
+       {
+           Tj [p] = j ;
+       }
+    }
+
+    return (UMFPACK_OK) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_defaults.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_defaults.c
new file mode 100644 (file)
index 0000000..8de4c1b
--- /dev/null
@@ -0,0 +1,119 @@
+/* ========================================================================== */
+/* === UMFPACK_defaults ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Sets default control parameters.  See umfpack_defaults.h
+    for details.
+*/
+
+#include "umf_internal.h"
+
+GLOBAL void UMFPACK_defaults
+(
+    double Control [UMFPACK_CONTROL]
+)
+{
+    Int i ;
+
+    if (!Control)
+    {
+       /* silently return if no Control array */
+       return ;
+    }
+
+    for (i = 0 ; i < UMFPACK_CONTROL ; i++)
+    {
+       Control [i] = 0 ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* default control settings: can be modified at run-time */
+    /* ---------------------------------------------------------------------- */
+
+    /* used in UMFPACK_report_* routines: */
+    Control [UMFPACK_PRL] = UMFPACK_DEFAULT_PRL ;
+
+    /* used in UMFPACK_*symbolic: */
+    Control [UMFPACK_DENSE_ROW] = UMFPACK_DEFAULT_DENSE_ROW ;
+    Control [UMFPACK_DENSE_COL] = UMFPACK_DEFAULT_DENSE_COL ;
+    Control [UMFPACK_AMD_DENSE] = UMFPACK_DEFAULT_AMD_DENSE ;
+    Control [UMFPACK_STRATEGY] = UMFPACK_DEFAULT_STRATEGY ;
+    Control [UMFPACK_2BY2_TOLERANCE] = UMFPACK_DEFAULT_2BY2_TOLERANCE ;
+    Control [UMFPACK_AGGRESSIVE] = UMFPACK_DEFAULT_AGGRESSIVE ;
+
+    /* used in UMFPACK_numeric: */
+    Control [UMFPACK_PIVOT_TOLERANCE] = UMFPACK_DEFAULT_PIVOT_TOLERANCE ;
+    Control [UMFPACK_SYM_PIVOT_TOLERANCE] = UMFPACK_DEFAULT_SYM_PIVOT_TOLERANCE;
+    Control [UMFPACK_BLOCK_SIZE] = UMFPACK_DEFAULT_BLOCK_SIZE ;
+    Control [UMFPACK_ALLOC_INIT] = UMFPACK_DEFAULT_ALLOC_INIT ;
+    Control [UMFPACK_FRONT_ALLOC_INIT] = UMFPACK_DEFAULT_FRONT_ALLOC_INIT ;
+    Control [UMFPACK_SCALE] = UMFPACK_DEFAULT_SCALE ;
+
+    /* used in UMFPACK_*solve: */
+    Control [UMFPACK_IRSTEP] = UMFPACK_DEFAULT_IRSTEP ;
+
+    /* ---------------------------------------------------------------------- */
+    /* compile-time settings: cannot be modified at run-time */
+    /* ---------------------------------------------------------------------- */
+
+#ifdef USE_NO_BLAS
+    /* do not use the BLAS - use in-line C code instead */
+    Control [UMFPACK_COMPILED_WITH_BLAS] = 0 ;
+#else
+    /* use externally-provided BLAS (dgemm, dger, dgemv, zgemm, zgeru, zgemv) */
+    Control [UMFPACK_COMPILED_WITH_BLAS] = 1 ;
+#endif
+
+#ifdef MATLAB_MEX_FILE
+    /* use mxMalloc, mxFree, mxRealloc, and mexPrintf */
+    /* use mxAssert if debugging is enabled */
+    Control [UMFPACK_COMPILED_FOR_MATLAB] = 1 ;
+#else
+#ifdef MATHWORKS
+    /* use internal utMalloc, utFree, utRealloc, and utPrintf routines. */
+    /* use utDivideComplex and utFdlibm_hypot for complex version. */
+    /* use utAssert if debugging is enabled. */
+    Control [UMFPACK_COMPILED_FOR_MATLAB] = 2 ;
+#else
+    /* use ANSI C malloc, free, realloc, and print */
+    /* use ANSI C assert if debugging is enabled */
+    Control [UMFPACK_COMPILED_FOR_MATLAB] = 0 ;
+#endif
+#endif
+
+#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/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_free_numeric.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_free_numeric.c
new file mode 100644 (file)
index 0000000..ec19adf
--- /dev/null
@@ -0,0 +1,58 @@
+/* ========================================================================== */
+/* === UMFPACK_free_numeric ================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*  User-callable.  Free the entire Numeric object (consists of 11 to 13
+ *  malloc'd objects.  See UMFPACK_free_numeric.h for details.
+ */
+
+#include "umf_internal.h"
+#include "umf_free.h"
+
+GLOBAL void UMFPACK_free_numeric
+(
+    void **NumericHandle
+)
+{
+
+    NumericType *Numeric ;
+    if (!NumericHandle)
+    {
+       return ;
+    }
+    Numeric = *((NumericType **) NumericHandle) ;
+    if (!Numeric)
+    {
+       return ;
+    }
+
+    /* these 9 objects always exist */
+    (void) UMF_free ((void *) Numeric->D) ;
+    (void) UMF_free ((void *) Numeric->Rperm) ;
+    (void) UMF_free ((void *) Numeric->Cperm) ;
+    (void) UMF_free ((void *) Numeric->Lpos) ;
+    (void) UMF_free ((void *) Numeric->Lilen) ;
+    (void) UMF_free ((void *) Numeric->Lip) ;
+    (void) UMF_free ((void *) Numeric->Upos) ;
+    (void) UMF_free ((void *) Numeric->Uilen) ;
+    (void) UMF_free ((void *) Numeric->Uip) ;
+
+    /* Rs does not exist if scaling was not performed */
+    (void) UMF_free ((void *) Numeric->Rs) ;
+
+    /* Upattern can only exist for singular or rectangular matrices */
+    (void) UMF_free ((void *) Numeric->Upattern) ;
+
+    /* these 2 objects always exist */
+    (void) UMF_free ((void *) Numeric->Memory) ;
+    (void) UMF_free ((void *) Numeric) ;
+
+    *NumericHandle = (void *) NULL ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_free_symbolic.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_free_symbolic.c
new file mode 100644 (file)
index 0000000..347727f
--- /dev/null
@@ -0,0 +1,57 @@
+/* ========================================================================== */
+/* === UMFPACK_free_symbolic ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  See umfpack_free_symbolic.h for details.
+    All 10 objects comprising the Symbolic object are free'd via UMF_free.
+*/
+
+#include "umf_internal.h"
+#include "umf_free.h"
+
+GLOBAL void UMFPACK_free_symbolic
+(
+    void **SymbolicHandle
+)
+{
+
+    SymbolicType *Symbolic ;
+    if (!SymbolicHandle)
+    {
+       return ;
+    }
+    Symbolic = *((SymbolicType **) SymbolicHandle) ;
+    if (!Symbolic)
+    {
+       return ;
+    }
+
+    (void) UMF_free ((void *) Symbolic->Cperm_init) ;
+    (void) UMF_free ((void *) Symbolic->Rperm_init) ;
+    (void) UMF_free ((void *) Symbolic->Front_npivcol) ;
+    (void) UMF_free ((void *) Symbolic->Front_parent) ;
+    (void) UMF_free ((void *) Symbolic->Front_1strow) ;
+    (void) UMF_free ((void *) Symbolic->Front_leftmostdesc) ;
+    (void) UMF_free ((void *) Symbolic->Chain_start) ;
+    (void) UMF_free ((void *) Symbolic->Chain_maxrows) ;
+    (void) UMF_free ((void *) Symbolic->Chain_maxcols) ;
+    (void) UMF_free ((void *) Symbolic->Cdeg) ;
+    (void) UMF_free ((void *) Symbolic->Rdeg) ;
+
+    /* only when dense rows are present */
+    (void) UMF_free ((void *) Symbolic->Esize) ;
+
+    /* only when diagonal pivoting is prefered */
+    (void) UMF_free ((void *) Symbolic->Diagonal_map) ;
+
+    (void) UMF_free ((void *) Symbolic) ;
+    *SymbolicHandle = (void *) NULL ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_get_lunz.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_get_lunz.c
new file mode 100644 (file)
index 0000000..37ac8bf
--- /dev/null
@@ -0,0 +1,56 @@
+/* ========================================================================== */
+/* === UMFPACK_get_lunz ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Determines the number of nonzeros in L and U, and the size
+    of L and U.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_numeric.h"
+
+GLOBAL Int UMFPACK_get_lunz
+(
+    Int *lnz,
+    Int *unz,
+    Int *n_row,
+    Int *n_col,
+    Int *nz_udiag,
+    void *NumericHandle
+)
+{
+    NumericType *Numeric ;
+
+    Numeric = (NumericType *) NumericHandle ;
+
+    if (!UMF_valid_numeric (Numeric))
+    {
+       return (UMFPACK_ERROR_invalid_Numeric_object) ;
+    }
+    if (!lnz || !unz || !n_row || !n_col || !nz_udiag)
+    {
+       return (UMFPACK_ERROR_argument_missing) ;
+    }
+
+    *n_row = Numeric->n_row ;
+    *n_col = Numeric->n_col ;
+
+    /* number of nz's in L below diagonal, plus the unit diagonal of L */
+    *lnz = Numeric->lnz + MIN (Numeric->n_row, Numeric->n_col) ;
+
+    /* number of nz's in U above diagonal, plus nz's on diagaonal of U */
+    *unz = Numeric->unz + Numeric->nnzpiv ;
+
+    /* number of nz's on the diagonal */
+    *nz_udiag = Numeric->nnzpiv ;
+
+    return (UMFPACK_OK) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_get_numeric.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_get_numeric.c
new file mode 100644 (file)
index 0000000..e270b1e
--- /dev/null
@@ -0,0 +1,980 @@
+/* ========================================================================== */
+/* === UMFPACK_get_numeric ================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Gets the LU factors and the permutation vectors held in the
+    Numeric object.  L is returned in sparse row form with sorted rows, U is
+    returned in sparse column form with sorted columns, and P and Q are
+    returned as permutation vectors.  See umfpack_get_numeric.h for a more
+    detailed description.
+
+    Returns TRUE if successful, FALSE if the Numeric object is invalid or
+    if out of memory.
+
+    Dynamic memory usage:  calls UMF_malloc twice, for a total space of
+    2*n integers, and then frees all of it via UMF_free when done.
+
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_numeric.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+
+#ifndef NDEBUG
+PRIVATE Int init_count ;
+#endif
+
+PRIVATE void get_L
+(
+    Int Lp [ ],
+    Int Lj [ ],
+    double Lx [ ],
+#ifdef COMPLEX
+    double Lz [ ],
+#endif
+    NumericType *Numeric,
+    Int Pattern [ ],
+    Int Wi [ ]
+) ;
+
+PRIVATE void get_U
+(
+    Int Up [ ],
+    Int Ui [ ],
+    double Ux [ ],
+#ifdef COMPLEX
+    double Uz [ ],
+#endif
+    NumericType *Numeric,
+    Int Pattern [ ],
+    Int Wi [ ]
+) ;
+
+/* ========================================================================== */
+/* === UMFPACK_get_numeric ================================================== */
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_get_numeric
+(
+    Int Lp [ ],
+    Int Lj [ ],
+    double Lx [ ],
+#ifdef COMPLEX
+    double Lz [ ],
+#endif
+    Int Up [ ],
+    Int Ui [ ],
+    double Ux [ ],
+#ifdef COMPLEX
+    double Uz [ ],
+#endif
+    Int P [ ],
+    Int Q [ ],
+    double Dx [ ],
+#ifdef COMPLEX
+    double Dz [ ],
+#endif
+    Int *p_do_recip,
+    double Rs [ ],
+    void *NumericHandle
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    NumericType *Numeric ;
+    Int getL, getU, *Rperm, *Cperm, k, nn, n_row, n_col, *Wi, *Pattern,
+       n_inner ;
+    double *Rs1 ;
+    Entry *D ;
+
+#ifndef NDEBUG
+    init_count = UMF_malloc_count ;
+#endif
+
+    Wi = (Int *) NULL ;
+    Pattern = (Int *) NULL ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check input parameters */
+    /* ---------------------------------------------------------------------- */
+
+    Numeric = (NumericType *) NumericHandle ;
+    if (!UMF_valid_numeric (Numeric))
+    {
+       return (UMFPACK_ERROR_invalid_Numeric_object) ;
+    }
+
+    n_row = Numeric->n_row ;
+    n_col = Numeric->n_col ;
+    nn = MAX (n_row, n_col) ;
+    n_inner = MIN (n_row, n_col) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+#ifdef COMPLEX
+    getL = Lp && Lj && Lx && Lz ;
+    getU = Up && Ui && Ux && Uz ;
+#else
+    getL = Lp && Lj && Lx ;
+    getU = Up && Ui && Ux ;
+#endif
+
+    if (getL || getU)
+    {
+       Wi = (Int *) UMF_malloc (nn, sizeof (Int)) ;
+       Pattern = (Int *) UMF_malloc (nn, sizeof (Int)) ;
+       if (!Wi || !Pattern)
+       {
+           (void) UMF_free ((void *) Wi) ;
+           (void) UMF_free ((void *) Pattern) ;
+           ASSERT (UMF_malloc_count == init_count) ;
+           DEBUGm4 (("out of memory: get numeric\n")) ;
+           return (UMFPACK_ERROR_out_of_memory) ;
+       }
+       ASSERT (UMF_malloc_count == init_count + 2) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get contents of Numeric */
+    /* ---------------------------------------------------------------------- */
+
+    if (P != (Int *) NULL)
+    {
+       Rperm = Numeric->Rperm ;
+       for (k = 0 ; k < n_row ; k++)
+       {
+           P [k] = Rperm [k] ;
+       }
+    }
+
+    if (Q != (Int *) NULL)
+    {
+       Cperm = Numeric->Cperm ;
+       for (k = 0 ; k < n_col ; k++)
+       {
+           Q [k] = Cperm [k] ;
+       }
+    }
+
+    if (getL)
+    {
+       get_L (Lp, Lj, Lx,
+#ifdef COMPLEX
+           Lz,
+#endif
+           Numeric, Pattern, Wi) ;
+    }
+
+    if (getU)
+    {
+       get_U (Up, Ui, Ux,
+#ifdef COMPLEX
+           Uz,
+#endif
+           Numeric, Pattern, Wi) ;
+    }
+
+    if (Dx != (double *) NULL)
+    {
+       D = Numeric->D ;
+       for (k = 0 ; k < n_inner ; k++)
+       {
+           Dx [k] = REAL_COMPONENT (D [k]) ;
+       }
+    }
+
+#ifdef COMPLEX
+    if (Dz != (double *) NULL)
+    {
+       D = Numeric->D ;
+       for (k = 0 ; k < n_inner ; k++)
+       {
+           Dz [k] = IMAG_COMPONENT (D [k]) ;
+       }
+    }
+#endif
+
+    /* return the flag stating whether the scale factors are to be multiplied,
+     * or divided.   If do_recip is TRUE, multiply.  Otherwise, divided.
+     * If NRECIPROCAL is defined at compile time, the scale factors are always
+     * to be used by dividing.
+     */
+    if (p_do_recip != (Int *) NULL)
+    {
+#ifndef NRECIPROCAL
+       *p_do_recip = Numeric->do_recip ;
+#else
+       *p_do_recip = FALSE ;
+#endif
+    }
+
+    if (Rs != (double *) NULL)
+    {
+       Rs1 = Numeric->Rs ;
+       if (Rs1 == (double *) NULL)
+       {
+           /* R is the identity matrix.  */
+           for (k = 0 ; k < n_row ; k++)
+           {
+               Rs [k] = 1.0 ;
+           }
+       }
+       else
+       {
+           for (k = 0 ; k < n_row ; k++)
+           {
+               Rs [k] = Rs1 [k] ;
+           }
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* free the workspace */
+    /* ---------------------------------------------------------------------- */
+
+    (void) UMF_free ((void *) Wi) ;
+    (void) UMF_free ((void *) Pattern) ;
+    ASSERT (UMF_malloc_count == init_count) ;
+
+    return (UMFPACK_OK) ;
+}
+
+
+/* ========================================================================== */
+/* === get_L ================================================================ */
+/* ========================================================================== */
+
+/*
+    The matrix L is stored in the following arrays in the Numeric object:
+
+       Int Lpos [0..npiv]
+       Int Lip [0..npiv], index into Numeric->Memory
+       Int Lilen [0..npiv]
+       Unit *(Numeric->Memory), pointer to memory space holding row indices
+               and numerical values
+
+    where npiv is the number of pivot entries found.  If A is n_row-by-n_col,
+    then npiv <= MIN (n_row,n_col).
+
+    Let L_k denote the pattern of entries in column k of L (excluding the
+    diagonal).
+
+    An Lchain is a sequence of columns of L whose nonzero patterns are related.
+    The start of an Lchain is denoted by a negative value of Lip [k].
+
+    To obtain L_k:
+
+    (1)        If column k starts an Lchain, then L_k is stored in its entirety.
+       |Lip [k]| is an index into Numeric->Memory for the integer row indices
+       in L_k.  The number of entries in the column is |L_k| = Lilen [k].
+       This defines the pattern of the "leading" column of this chain.
+       Lpos [k] is not used for the first column in the chain.  Column zero
+       is always a leading column.
+
+    (2) If column k does not start an Lchain, then L_k is represented as a
+       superset of L_k-1.  Define Lnew_k such that (L_k-1 - {k} union Lnew_k)
+       = L_k, where Lnew_k and (L_k-1)-{k} are disjoint.  Lnew_k are the
+       entries in L_k that are not in L_k-1.  Lpos [k] holds the position of
+       pivot row index k in the prior pattern L_k-1 (if it is present), so
+       that the set subtraction (L_k-1)-{k} can be computed quickly, when
+       computing the pattern of L_k from L_k-1.  The number of new entries in
+       L_k is stored in Lilen [k] = |Lnew_k|.
+
+       Note that this means we must have the pattern L_k-1 to compute L_k.
+
+    In both cases (1) and (2), we obtain the pattern L_k.
+
+    The numerical values are stored in Numeric->Memory, starting at the index
+    |Lip [k]| + Lilen [k].  It is stored in the same order as the entries
+    in L_k, after L_k is obtained from cases (1) or (2), above.
+
+    The advantage of using this "packed" data structure is that it can
+    dramatically reduce the amount of storage needed for the pattern of L.
+    The disadvantage is that it can be difficult for the user to access,
+    and it does not match the sparse matrix data structure used in MATLAB.
+    Thus, this routine is provided to create a conventional sparse matrix
+    data structure for L, in sparse-row form.  A row-form of L appears to
+    MATLAB to be a column-oriented from of the transpose of L.  If you would
+    like a column-form of L, then use UMFPACK_transpose (an example of this
+    is in umfpackmex.c).
+
+*/
+/* ========================================================================== */
+
+PRIVATE void get_L
+(
+    Int Lp [ ],                /* of size n_row+1 */
+    Int Lj [ ],                /* of size lnz, where lnz = Lp [n_row] */
+    double Lx [ ],     /* of size lnz */
+#ifdef COMPLEX
+    double Lz [ ],     /* of size lnz */
+#endif
+    NumericType *Numeric,
+    Int Pattern [ ],   /* workspace of size n_row */
+    Int Wi [ ]         /* workspace of size n_row */
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int deg, *ip, j, row, n_row, n_col, n_inner, *Lpos, *Lilen, *Lip, p, llen,
+       lnz2, lp, newLchain, k, pos, npiv, *Li, n1 ;
+    Entry *xp, value, *Lval ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG4 (("get_L start:\n")) ;
+    n_row = Numeric->n_row ;
+    n_col = Numeric->n_col ;
+    n_inner = MIN (n_row, n_col) ;
+    npiv = Numeric->npiv ;
+    n1 = Numeric->n1 ;
+    Lpos = Numeric->Lpos ;
+    Lilen = Numeric->Lilen ;
+    Lip = Numeric->Lip ;
+    deg = 0 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* count the nonzeros in each row of L */
+    /* ---------------------------------------------------------------------- */
+
+#pragma ivdep
+    for (row = 0 ; row < n_inner ; row++)
+    {
+       /* include the diagonal entry in the row counts */
+       Wi [row] = 1 ;
+    }
+#pragma ivdep
+    for (row = n_inner ; row < n_row ; row++)
+    {
+       Wi [row] = 0 ;
+    }
+
+    /* singletons */
+    for (k = 0 ; k < n1 ; k++)
+    {
+       DEBUG4 (("Singleton k "ID"\n", k)) ;
+       deg = Lilen [k] ;
+       if (deg > 0)
+       {
+           lp = Lip [k] ;
+           Li = (Int *) (Numeric->Memory + lp) ;
+           lp += UNITS (Int, deg) ;
+           Lval = (Entry *) (Numeric->Memory + lp) ;
+           for (j = 0 ; j < deg ; j++)
+           {
+               row = Li [j] ;
+               value = Lval [j] ;
+               DEBUG4 (("  row "ID"  k "ID" value", row, k)) ;
+               EDEBUG4 (value) ;
+               DEBUG4 (("\n")) ;
+               if (IS_NONZERO (value))
+               {
+                   Wi [row]++ ;
+               }
+           }
+       }
+    }
+
+    /* non-singletons */
+    for (k = n1 ; k < npiv ; k++)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* make column of L in Pattern [0..deg-1] */
+       /* ------------------------------------------------------------------ */
+
+       lp = Lip [k] ;
+       newLchain = (lp < 0) ;
+       if (newLchain)
+       {
+           lp = -lp ;
+           deg = 0 ;
+           DEBUG4 (("start of chain for column of L\n")) ;
+       }
+
+       /* remove pivot row */
+       pos = Lpos [k] ;
+       if (pos != EMPTY)
+       {
+           DEBUG4 (("  k "ID" removing row "ID" at position "ID"\n",
+           k, Pattern [pos], pos)) ;
+           ASSERT (!newLchain) ;
+           ASSERT (deg > 0) ;
+           ASSERT (pos >= 0 && pos < deg) ;
+           ASSERT (Pattern [pos] == k) ;
+           Pattern [pos] = Pattern [--deg] ;
+       }
+
+       /* concatenate the pattern */
+       ip = (Int *) (Numeric->Memory + lp) ;
+       llen = Lilen [k] ;
+       for (j = 0 ; j < llen ; j++)
+       {
+           row = *ip++ ;
+           DEBUG4 (("  row "ID"  k "ID"\n", row, k)) ;
+           ASSERT (row > k && row < n_row) ;
+           Pattern [deg++] = row ;
+       }
+
+       xp = (Entry *) (Numeric->Memory + lp + UNITS (Int, llen)) ;
+
+       for (j = 0 ; j < deg ; j++)
+       {
+           DEBUG4 (("  row "ID"  k "ID" value", Pattern [j], k)) ;
+           row = Pattern [j] ;
+           value = *xp++ ;
+           EDEBUG4 (value) ;
+           DEBUG4 (("\n")) ;
+           if (IS_NONZERO (value))
+           {
+               Wi [row]++ ;
+           }
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the final row form of L */
+    /* ---------------------------------------------------------------------- */
+
+    /* create the row pointers */
+    lnz2 = 0 ;
+    for (row = 0 ; row < n_row ; row++)
+    {
+       Lp [row] = lnz2 ;
+       lnz2 += Wi [row] ;
+       Wi [row] = Lp [row] ;
+    }
+    Lp [n_row] = lnz2 ;
+    ASSERT (Numeric->lnz + n_inner == lnz2) ;
+
+    /* add entries from the rows of L (singletons) */
+    for (k = 0 ; k < n1 ; k++)
+    {
+       DEBUG4 (("Singleton k "ID"\n", k)) ;
+       deg = Lilen [k] ;
+       if (deg > 0)
+       {
+           lp = Lip [k] ;
+           Li = (Int *) (Numeric->Memory + lp) ;
+           lp += UNITS (Int, deg) ;
+           Lval = (Entry *) (Numeric->Memory + lp) ;
+           for (j = 0 ; j < deg ; j++)
+           {
+               row = Li [j] ;
+               value = Lval [j] ;
+               DEBUG4 (("  row "ID"  k "ID" value", row, k)) ;
+               EDEBUG4 (value) ;
+               DEBUG4 (("\n")) ;
+               if (IS_NONZERO (value))
+               {
+                   p = Wi [row]++ ;
+                   Lj [p] = k ;
+                   Lx [p] = REAL_COMPONENT (value) ;
+#ifdef COMPLEX
+                   Lz [p] = IMAG_COMPONENT (value) ;
+#endif
+               }
+           }
+       }
+    }
+
+    /* add entries from the rows of L (non-singletons) */
+    for (k = n1 ; k < npiv ; k++)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* make column of L in Pattern [0..deg-1] */
+       /* ------------------------------------------------------------------ */
+
+       lp = Lip [k] ;
+       newLchain = (lp < 0) ;
+       if (newLchain)
+       {
+           lp = -lp ;
+           deg = 0 ;
+           DEBUG4 (("start of chain for column of L\n")) ;
+       }
+
+       /* remove pivot row */
+       pos = Lpos [k] ;
+       if (pos != EMPTY)
+       {
+           DEBUG4 (("  k "ID" removing row "ID" at position "ID"\n",
+           k, Pattern [pos], pos)) ;
+           ASSERT (!newLchain) ;
+           ASSERT (deg > 0) ;
+           ASSERT (pos >= 0 && pos < deg) ;
+           ASSERT (Pattern [pos] == k) ;
+           Pattern [pos] = Pattern [--deg] ;
+       }
+
+       /* concatenate the pattern */
+       ip = (Int *) (Numeric->Memory + lp) ;
+       llen = Lilen [k] ;
+       for (j = 0 ; j < llen ; j++)
+       {
+           row = *ip++ ;
+           DEBUG4 (("  row "ID"  k "ID"\n", row, k)) ;
+           ASSERT (row > k) ;
+           Pattern [deg++] = row ;
+       }
+
+       xp = (Entry *) (Numeric->Memory + lp + UNITS (Int, llen)) ;
+
+       for (j = 0 ; j < deg ; j++)
+       {
+           DEBUG4 (("  row "ID"  k "ID" value", Pattern [j], k)) ;
+           row = Pattern [j] ;
+           value = *xp++ ;
+           EDEBUG4 (value) ;
+           DEBUG4 (("\n")) ;
+           if (IS_NONZERO (value))
+           {
+               p = Wi [row]++ ;
+               Lj [p] = k ;
+               Lx [p] = REAL_COMPONENT (value) ;
+#ifdef COMPLEX
+               Lz [p] = IMAG_COMPONENT (value) ;
+#endif
+           }
+       }
+    }
+
+    /* add all of the diagonal entries (L is unit diagonal) */
+    for (row = 0 ; row < n_inner ; row++)
+    {
+       p = Wi [row]++ ;
+       Lj [p] = row ;
+       Lx [p] = 1. ;
+#ifdef COMPLEX
+       Lz [p] = 0. ;
+#endif
+       ASSERT (Wi [row] == Lp [row+1]) ;
+    }
+
+#ifndef NDEBUG
+    DEBUG6 (("L matrix (stored by rows):")) ;
+    UMF_dump_col_matrix (Lx,
+#ifdef COMPLEX
+       Lz,
+#endif
+       Lj, Lp, n_inner, n_row, Numeric->lnz+n_inner) ;
+#endif
+
+    DEBUG4 (("get_L done:\n")) ;
+}
+
+
+/* ========================================================================== */
+/* === get_U ================================================================ */
+/* ========================================================================== */
+
+/*
+    The matrix U is stored in the following arrays in the Numeric object:
+
+       Int Upos [0..npiv]
+       Int Uip [0..npiv], index into Numeric->Memory
+       Int Uilen [0..npiv]
+       Unit *(Numeric->Memory), pointer to memory space holding column indices
+               and numerical values
+
+    where npiv is the number of pivot entries found.  If A is n_row-by-n_col,
+    then npiv <= MIN (n_row,n_col).
+
+    Let U_k denote the pattern of entries in row k of U (excluding the
+    diagonal).
+
+    A Uchain is a sequence of columns of U whose nonzero patterns are related.
+    The start of a Uchain is denoted by a negative value of Uip [k].
+
+    To obtain U_k-1:
+
+    (1) If row k is the start of a Uchain then Uip [k] is negative and |Uip [k]|
+       is an index into Numeric->Memory for the integer column indices in
+       U_k-1.  The number of entries in the row is |U_k-1| = Uilen [k].  This
+       defines the pattern of the "trailing" row of this chain that ends at
+       row k-1.
+
+
+    (2) If row k is not the start of a Uchain, then U_k-1 is a subset of U_k.
+       The indices in U_k are arranged so that last Uilen [k] entries of
+       U_k are those indices not in U_k-1.  Next, the pivot column index k is
+       added if it appears in row U_k-1 (it never appears in U_k).  Upos [k]
+       holds the position of pivot column index k in the pattern U_k-1 (if it
+       is present), so that the set union (U_k-1)+{k} can be computed quickly,
+       when computing the pattern of U_k-1 from U_k.
+
+       Note that this means we must have the pattern U_k to compute L_k-1.
+
+    In both cases (1) and (2), we obtain the pattern U_k.
+
+    The numerical values are stored in Numeric->Memory.  If k is the start of a
+    Uchain, then the offset is |Uip [k]| plus the size of the space needed to
+    store the pattern U_k-1.  Otherwise, Uip [k] is the offset itself of the
+    numerical values, since in this case no pattern is stored.
+    The numerical values are stored in the same order as the entries in U_k,
+    after U_k is obtained from cases (1) or (2), above.
+
+    The advantage of using this "packed" data structure is that it can
+    dramatically reduce the amount of storage needed for the pattern of U.
+    The disadvantage is that it can be difficult for the user to access,
+    and it does not match the sparse matrix data structure used in MATLAB.
+    Thus, this routine is provided to create a conventional sparse matrix
+    data structure for U, in sparse-column form.
+
+*/
+/* ========================================================================== */
+
+PRIVATE void get_U
+(
+    Int Up [ ],                /* of size n_col+1 */
+    Int Ui [ ],                /* of size unz, where unz = Up [n_col] */
+    double Ux [ ],     /* of size unz */
+#ifdef COMPLEX
+    double Uz [ ],     /* of size unz */
+#endif
+    NumericType *Numeric,
+    Int Pattern [ ],   /* workspace of size n_col */
+    Int Wi [ ]         /* workspace of size n_col */
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int deg, j, *ip, col, *Upos, *Uilen, *Uip, n_col, ulen, *Usi,
+       unz2, p, k, up, newUchain, pos, npiv, n1 ;
+    Entry *xp, *D, value, *Uval ;
+
+#ifndef NDEBUG
+    Int nnzpiv = 0 ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG4 (("get_U start:\n")) ;
+    n_col = Numeric->n_col ;
+    n1 = Numeric->n1 ;
+    npiv = Numeric->npiv ;
+    Upos = Numeric->Upos ;
+    Uilen = Numeric->Uilen ;
+    Uip = Numeric->Uip ;
+    D = Numeric->D ;
+
+    /* ---------------------------------------------------------------------- */
+    /* count the nonzeros in each column of U */
+    /* ---------------------------------------------------------------------- */
+
+    for (col = 0 ; col < npiv ; col++)
+    {
+       /* include the diagonal entry in the column counts */
+       DEBUG4 (("D ["ID"] = ", col)) ;
+       EDEBUG4 (D [col]) ;
+       Wi [col] = IS_NONZERO (D [col]) ;
+       DEBUG4 ((" is nonzero: "ID"\n", Wi [col])) ;
+#ifndef NDEBUG
+       nnzpiv += IS_NONZERO (D [col]) ;
+#endif
+    }
+    DEBUG4 (("nnzpiv "ID" "ID"\n", nnzpiv, Numeric->nnzpiv)) ;
+    ASSERT (nnzpiv == Numeric->nnzpiv) ;
+    for (col = npiv ; col < n_col ; col++)
+    {
+       /* diagonal entries are zero for structurally singular part */
+       Wi [col] = 0 ;
+    }
+
+    deg = Numeric->ulen ;
+    if (deg > 0)
+    {
+       /* make last pivot row of U (singular matrices only) */
+       DEBUG0 (("Last pivot row of U: ulen "ID"\n", deg)) ;
+       for (j = 0 ; j < deg ; j++)
+       {
+           Pattern [j] = Numeric->Upattern [j] ;
+           DEBUG0 (("    column "ID"\n", Pattern [j])) ;
+       }
+    }
+
+    /* non-singletons */
+    for (k = npiv-1 ; k >= n1 ; k--)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* use row k of U */
+       /* ------------------------------------------------------------------ */
+
+       up = Uip [k] ;
+       ulen = Uilen [k] ;
+       newUchain = (up < 0) ;
+       if (newUchain)
+       {
+           up = -up ;
+           xp = (Entry *) (Numeric->Memory + up + UNITS (Int, ulen)) ;
+       }
+       else
+       {
+           xp = (Entry *) (Numeric->Memory + up) ;
+       }
+
+       for (j = 0 ; j < deg ; j++)
+       {
+           DEBUG4 (("  k "ID" col "ID" value\n", k, Pattern [j])) ;
+           col = Pattern [j] ;
+           ASSERT (col >= 0 && col < n_col) ;
+           value = *xp++ ;
+           EDEBUG4 (value) ;
+           DEBUG4 (("\n")) ;
+           if (IS_NONZERO (value))
+           {
+               Wi [col]++ ;
+           }
+       }
+
+       /* ------------------------------------------------------------------ */
+       /* make row k-1 of U in Pattern [0..deg-1] */
+       /* ------------------------------------------------------------------ */
+
+       if (k == n1) break ;
+
+       if (newUchain)
+       {
+           /* next row is a new Uchain */
+           deg = ulen ;
+           DEBUG4 (("end of chain for row of U "ID" deg "ID"\n", k-1, deg)) ;
+           ip = (Int *) (Numeric->Memory + up) ;
+           for (j = 0 ; j < deg ; j++)
+           {
+               col = *ip++ ;
+               DEBUG4 (("  k "ID" col "ID"\n", k-1, col)) ;
+               ASSERT (k <= col) ;
+               Pattern [j] = col ;
+           }
+       }
+       else
+       {
+           deg -= ulen ;
+           DEBUG4 (("middle of chain for row of U "ID" deg "ID"\n", k-1, deg));
+           ASSERT (deg >= 0) ;
+           pos = Upos [k] ;
+           if (pos != EMPTY)
+           {
+               /* add the pivot column */
+               DEBUG4 (("k "ID" add pivot entry at position "ID"\n", k, pos)) ;
+               ASSERT (pos >= 0 && pos <= deg) ;
+               Pattern [deg++] = Pattern [pos] ;
+               Pattern [pos] = k ;
+           }
+       }
+    }
+
+    /* singletons */
+    for (k = n1 - 1 ; k >= 0 ; k--)
+    {
+       deg = Uilen [k] ;
+       DEBUG4 (("Singleton k "ID"\n", k)) ;
+       if (deg > 0)
+       {
+           up = Uip [k] ;
+           Usi = (Int *) (Numeric->Memory + up) ;
+           up += UNITS (Int, deg) ;
+           Uval = (Entry *) (Numeric->Memory + up) ;
+           for (j = 0 ; j < deg ; j++)
+           {
+               col = Usi [j] ;
+               value = Uval [j] ;
+               DEBUG4 (("  k "ID" col "ID" value", k, col)) ;
+               EDEBUG4 (value) ;
+               DEBUG4 (("\n")) ;
+               if (IS_NONZERO (value))
+               {
+                   Wi [col]++ ;
+               }
+           }
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the final column form of U */
+    /* ---------------------------------------------------------------------- */
+
+    /* create the column pointers */
+    unz2 = 0 ;
+    for (col = 0 ; col < n_col ; col++)
+    {
+       Up [col] = unz2 ;
+       unz2 += Wi [col] ;
+    }
+    Up [n_col] = unz2 ;
+    DEBUG1 (("Numeric->unz "ID"  npiv "ID" nnzpiv "ID" unz2 "ID"\n",
+       Numeric->unz, npiv, Numeric->nnzpiv, unz2)) ;
+    ASSERT (Numeric->unz + Numeric->nnzpiv == unz2) ;
+
+    for (col = 0 ; col < n_col ; col++)
+    {
+       Wi [col] = Up [col+1] ;
+    }
+
+    /* add all of the diagonal entries */
+    for (col = 0 ; col < npiv ; col++)
+    {
+       if (IS_NONZERO (D [col]))
+       {
+           p = --(Wi [col]) ;
+           Ui [p] = col ;
+           Ux [p] = REAL_COMPONENT (D [col]) ;
+#ifdef COMPLEX
+           Uz [p] = IMAG_COMPONENT (D [col]) ;
+#endif
+       }
+    }
+
+    /* add all the entries from the rows of U */
+
+    deg = Numeric->ulen ;
+    if (deg > 0)
+    {
+       /* make last pivot row of U (singular matrices only) */
+       for (j = 0 ; j < deg ; j++)
+       {
+           Pattern [j] = Numeric->Upattern [j] ;
+       }
+    }
+
+    /* non-singletons */
+    for (k = npiv-1 ; k >= n1 ; k--)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* use row k of U */
+       /* ------------------------------------------------------------------ */
+
+       up = Uip [k] ;
+       ulen = Uilen [k] ;
+       newUchain = (up < 0) ;
+       if (newUchain)
+       {
+           up = -up ;
+           xp = (Entry *) (Numeric->Memory + up + UNITS (Int, ulen)) ;
+       }
+       else
+       {
+           xp = (Entry *) (Numeric->Memory + up) ;
+       }
+
+       xp += deg ;
+       for (j = deg-1 ; j >= 0 ; j--)
+       {
+           DEBUG4 (("  k "ID" col "ID" value", k, Pattern [j])) ;
+           col = Pattern [j] ;
+           ASSERT (col >= 0 && col < n_col) ;
+           value = *(--xp) ;
+           EDEBUG4 (value) ;
+           DEBUG4 (("\n")) ;
+           if (IS_NONZERO (value))
+           {
+               p = --(Wi [col]) ;
+               Ui [p] = k ;
+               Ux [p] = REAL_COMPONENT (value) ;
+#ifdef COMPLEX
+               Uz [p] = IMAG_COMPONENT (value) ;
+#endif
+           }
+       }
+
+       /* ------------------------------------------------------------------ */
+       /* make row k-1 of U in Pattern [0..deg-1] */
+       /* ------------------------------------------------------------------ */
+
+       if (newUchain)
+       {
+           /* next row is a new Uchain */
+           deg = ulen ;
+           DEBUG4 (("end of chain for row of U "ID" deg "ID"\n", k-1, deg)) ;
+           ip = (Int *) (Numeric->Memory + up) ;
+           for (j = 0 ; j < deg ; j++)
+           {
+               col = *ip++ ;
+               DEBUG4 (("  k "ID" col "ID"\n", k-1, col)) ;
+               ASSERT (k <= col) ;
+               Pattern [j] = col ;
+           }
+       }
+       else
+       {
+           deg -= ulen ;
+           DEBUG4 (("middle of chain for row of U "ID" deg "ID"\n", k-1, deg));
+           ASSERT (deg >= 0) ;
+           pos = Upos [k] ;
+           if (pos != EMPTY)
+           {
+               /* add the pivot column */
+               DEBUG4 (("k "ID" add pivot entry at position "ID"\n", k, pos)) ;
+               ASSERT (pos >= 0 && pos <= deg) ;
+               Pattern [deg++] = Pattern [pos] ;
+               Pattern [pos] = k ;
+           }
+       }
+    }
+
+    /* singletons */
+    for (k = n1 - 1 ; k >= 0 ; k--)
+    {
+       deg = Uilen [k] ;
+       DEBUG4 (("Singleton k "ID"\n", k)) ;
+       if (deg > 0)
+       {
+           up = Uip [k] ;
+           Usi = (Int *) (Numeric->Memory + up) ;
+           up += UNITS (Int, deg) ;
+           Uval = (Entry *) (Numeric->Memory + up) ;
+           for (j = 0 ; j < deg ; j++)
+           {
+               col = Usi [j] ;
+               value = Uval [j] ;
+               DEBUG4 (("  k "ID" col "ID" value", k, col)) ;
+               EDEBUG4 (value) ;
+               DEBUG4 (("\n")) ;
+               if (IS_NONZERO (value))
+               {
+                   p = --(Wi [col]) ;
+                   Ui [p] = k ;
+                   Ux [p] = REAL_COMPONENT (value) ;
+#ifdef COMPLEX
+                   Uz [p] = IMAG_COMPONENT (value) ;
+#endif
+               }
+           }
+       }
+    }
+
+#ifndef NDEBUG
+    DEBUG6 (("U matrix:")) ;
+    UMF_dump_col_matrix (Ux,
+#ifdef COMPLEX
+       Uz,
+#endif
+       Ui, Up, Numeric->n_row, n_col, Numeric->unz + Numeric->nnzpiv) ;
+#endif
+
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_get_symbolic.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_get_symbolic.c
new file mode 100644 (file)
index 0000000..6a88f37
--- /dev/null
@@ -0,0 +1,192 @@
+/* ========================================================================== */
+/* === UMFPACK_get_symbolic ================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Gets the symbolic information held in the Symbolic object.
+    See umfpack_get_symbolic.h for a more detailed description.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_symbolic.h"
+
+GLOBAL Int UMFPACK_get_symbolic
+(
+    Int *p_n_row,
+    Int *p_n_col,
+    Int *p_n1,                 /* number of singletons */
+    Int *p_nz,
+    Int *p_nfr,
+    Int *p_nchains,
+    Int P [ ],
+    Int Q [ ],
+    Int Front_npivcol [ ],
+    Int Front_parent [ ],
+    Int Front_1strow [ ],
+    Int Front_leftmostdesc [ ],
+    Int Chain_start [ ],
+    Int Chain_maxrows [ ],
+    Int Chain_maxcols [ ],
+    void *SymbolicHandle
+)
+{
+    SymbolicType *Symbolic ;
+    Int k, n_row, n_col, n1, nfr, nchains, *p ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    Symbolic = (SymbolicType *) SymbolicHandle ;
+    if (!UMF_valid_symbolic (Symbolic))
+    {
+       return (UMFPACK_ERROR_invalid_Symbolic_object) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get contents of Symbolic */
+    /* ---------------------------------------------------------------------- */
+
+    n_row = Symbolic->n_row ;
+    n_col = Symbolic->n_col ;
+    n1 = Symbolic->n1 ;
+    nfr = Symbolic->nfr ;
+    nchains = Symbolic->nchains ;
+
+    if (p_n_row)
+    {
+       *p_n_row = n_row ;
+    }
+
+    if (p_n_col)
+    {
+       *p_n_col = n_col ;
+    }
+
+    if (p_n1)
+    {
+       *p_n1 = n1 ;
+    }
+
+    if (p_nz)
+    {
+       *p_nz = Symbolic->nz ;
+    }
+
+    if (p_nfr)
+    {
+       *p_nfr = nfr ;
+    }
+
+    if (p_nchains)
+    {
+       *p_nchains = nchains ;
+    }
+
+    if (P != (Int *) NULL)
+    {
+       Int *Rperm_init, *Diagonal_map ;
+       Rperm_init = Symbolic->Rperm_init ;
+       Diagonal_map = Symbolic->Diagonal_map ;
+       if (Diagonal_map != (Int *) NULL)
+       {
+           ASSERT (n_row == n_col) ;
+           /* next pivot rows are found in the diagonal map */
+           for (k = 0 ; k < n_row ; k++)
+           {
+               P [k] = Rperm_init [Diagonal_map [k]] ;
+           }
+       }
+       else
+       {
+           /* there is no diagonal map.  */
+           for (k = 0 ; k < n_row ; k++)
+           {
+               P [k] = Rperm_init [k] ;
+           }
+       }
+    }
+
+    if (Q != (Int *) NULL)
+    {
+       p = Symbolic->Cperm_init ;
+       for (k = 0 ; k < n_col ; k++)
+       {
+           Q [k] = p [k] ;
+       }
+    }
+
+    if (Front_npivcol != (Int *) NULL)
+    {
+       p = Symbolic->Front_npivcol ;
+       for (k = 0 ; k <= nfr ; k++)
+       {
+           Front_npivcol [k] = p [k] ;
+       }
+    }
+
+    if (Front_parent != (Int *) NULL)
+    {
+       p = Symbolic->Front_parent ;
+       for (k = 0 ; k <= nfr ; k++)
+       {
+           Front_parent [k] = p [k] ;
+       }
+    }
+
+    if (Front_1strow != (Int *) NULL)
+    {
+       p = Symbolic->Front_1strow ;
+       for (k = 0 ; k <= nfr ; k++)
+       {
+           Front_1strow [k] = p [k] ;
+       }
+    }
+
+    if (Front_leftmostdesc != (Int *) NULL)
+    {
+       p = Symbolic->Front_leftmostdesc ;
+       for (k = 0 ; k <= nfr ; k++)
+       {
+           Front_leftmostdesc [k] = p [k] ;
+       }
+    }
+
+    if (Chain_start != (Int *) NULL)
+    {
+       p = Symbolic->Chain_start ;
+       for (k = 0 ; k <= nchains ; k++)
+       {
+           Chain_start [k] = p [k] ;
+       }
+    }
+
+    if (Chain_maxrows != (Int *) NULL)
+    {
+       p = Symbolic->Chain_maxrows ;
+       for (k = 0 ; k < nchains ; k++)
+       {
+           Chain_maxrows [k] = p [k] ;
+       }
+       Chain_maxrows [nchains] = 0 ;
+    }
+
+    if (Chain_maxcols != (Int *) NULL)
+    {
+       p = Symbolic->Chain_maxcols ;
+       for (k = 0 ; k < nchains ; k++)
+       {
+           Chain_maxcols [k] = p [k] ;
+       }
+       Chain_maxcols [nchains] = 0 ;
+    }
+
+    return (UMFPACK_OK) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_load_numeric.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_load_numeric.c
new file mode 100644 (file)
index 0000000..db98757
--- /dev/null
@@ -0,0 +1,162 @@
+/* ========================================================================== */
+/* === UMFPACK_load_numeric ================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Loads a Numeric object from a file created by
+    umfpack_*_save_numeric.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_numeric.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+
+#define READ(object,type,n) \
+{ \
+    object = (type *) UMF_malloc (n, sizeof (type)) ; \
+    if (object == (type *) NULL) \
+    { \
+       UMFPACK_free_numeric ((void **) &Numeric) ; \
+       fclose (f) ; \
+       return (UMFPACK_ERROR_out_of_memory) ; \
+    } \
+    if (fread (object, sizeof (type), n, f) != n) \
+    { \
+       UMFPACK_free_numeric ((void **) &Numeric) ; \
+       fclose (f) ; \
+       return (UMFPACK_ERROR_file_IO) ; \
+    } \
+    if (ferror (f)) \
+    { \
+       UMFPACK_free_numeric ((void **) &Numeric) ; \
+       fclose (f) ; \
+       return (UMFPACK_ERROR_file_IO) ; \
+    } \
+}
+
+/* ========================================================================== */
+/* === UMFPACK_load_numeric ================================================= */
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_load_numeric
+(
+    void **NumericHandle,
+    char *user_filename
+)
+{
+    NumericType *Numeric ;
+    char *filename ;
+    FILE *f ;
+
+    *NumericHandle = (void *) NULL ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get the filename, or use the default name if filename is NULL */
+    /* ---------------------------------------------------------------------- */
+
+    if (user_filename == (char *) NULL)
+    {
+       filename = "numeric.umf" ;
+    }
+    else
+    {
+       filename = user_filename ;
+    }
+    f = fopen (filename, "rb") ;
+    if (!f)
+    {
+       return (UMFPACK_ERROR_file_IO) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* read the Numeric header from the file, in binary */
+    /* ---------------------------------------------------------------------- */
+
+    Numeric = (NumericType *) UMF_malloc (1, sizeof (NumericType)) ;
+    if (Numeric == (NumericType *) NULL)
+    {
+       fclose (f) ;
+       return (UMFPACK_ERROR_out_of_memory) ;
+    }
+    if (fread (Numeric, sizeof (NumericType), 1, f) != 1)
+    {
+       (void) UMF_free ((void *) Numeric) ;
+       fclose (f) ;
+       return (UMFPACK_ERROR_file_IO) ;
+    }
+    if (ferror (f))
+    {
+       (void) UMF_free ((void *) Numeric) ;
+       fclose (f) ;
+       return (UMFPACK_ERROR_file_IO) ;
+    }
+
+    if (Numeric->valid != NUMERIC_VALID || Numeric->n_row <= 0 ||
+       Numeric->n_col <= 0 || Numeric->npiv < 0 || Numeric->ulen < 0 ||
+       Numeric->size <= 0)
+    {
+       /* Numeric does not point to a NumericType object */
+       (void) UMF_free ((void *) Numeric) ;
+       fclose (f) ;
+       return (UMFPACK_ERROR_invalid_Numeric_object) ;
+    }
+
+    Numeric->D        = (Entry *) NULL ;
+    Numeric->Rperm    = (Int *) NULL ;
+    Numeric->Cperm    = (Int *) NULL ;
+    Numeric->Lpos     = (Int *) NULL ;
+    Numeric->Lilen    = (Int *) NULL ;
+    Numeric->Lip      = (Int *) NULL ;
+    Numeric->Upos     = (Int *) NULL ;
+    Numeric->Uilen    = (Int *) NULL ;
+    Numeric->Uip      = (Int *) NULL ;
+    Numeric->Rs       = (double *) NULL ;
+    Numeric->Memory   = (Unit *) NULL ;
+    Numeric->Upattern = (Int *) NULL ;
+
+    /* umfpack_free_numeric can now be safely called if an error occurs */
+
+    /* ---------------------------------------------------------------------- */
+    /* read the rest of the Numeric object */
+    /* ---------------------------------------------------------------------- */
+
+    READ (Numeric->D,     Entry, MIN (Numeric->n_row, Numeric->n_col)+1) ;
+    READ (Numeric->Rperm, Int,   Numeric->n_row+1) ;
+    READ (Numeric->Cperm, Int,   Numeric->n_col+1) ;
+    READ (Numeric->Lpos,  Int,   Numeric->npiv+1) ;
+    READ (Numeric->Lilen, Int,   Numeric->npiv+1) ;
+    READ (Numeric->Lip,   Int,   Numeric->npiv+1) ;
+    READ (Numeric->Upos,  Int,   Numeric->npiv+1) ;
+    READ (Numeric->Uilen, Int,   Numeric->npiv+1) ;
+    READ (Numeric->Uip,   Int,   Numeric->npiv+1) ;
+    if (Numeric->scale != UMFPACK_SCALE_NONE)
+    {
+       READ (Numeric->Rs, double, Numeric->n_row) ;
+    }
+    if (Numeric->ulen > 0)
+    {
+       READ (Numeric->Upattern, Int, Numeric->ulen+1) ;
+    }
+    READ (Numeric->Memory, Unit, Numeric->size) ;
+
+    /* close the file */
+    fclose (f) ;
+
+    /* make sure the Numeric object is valid */
+    if (!UMF_valid_numeric (Numeric))
+    {
+       UMFPACK_free_numeric ((void **) &Numeric) ;
+       return (UMFPACK_ERROR_invalid_Numeric_object) ;
+    }
+
+    *NumericHandle = (void *) Numeric ;
+    return (UMFPACK_OK) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_load_symbolic.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_load_symbolic.c
new file mode 100644 (file)
index 0000000..dceea05
--- /dev/null
@@ -0,0 +1,166 @@
+/* ========================================================================== */
+/* === UMFPACK_load_symbolic ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Loads a Symbolic object from a file created by
+    umfpack_*_save_symbolic.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_symbolic.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+
+#define READ(object,type,n) \
+{ \
+    object = (type *) UMF_malloc (n, sizeof (type)) ; \
+    if (object == (type *) NULL) \
+    { \
+       UMFPACK_free_symbolic ((void **) &Symbolic) ; \
+       fclose (f) ; \
+       return (UMFPACK_ERROR_out_of_memory) ; \
+    } \
+    if (fread (object, sizeof (type), n, f) != n) \
+    { \
+       UMFPACK_free_symbolic ((void **) &Symbolic) ; \
+       fclose (f) ; \
+       return (UMFPACK_ERROR_file_IO) ; \
+    } \
+    if (ferror (f)) \
+    { \
+       UMFPACK_free_symbolic ((void **) &Symbolic) ; \
+       fclose (f) ; \
+       return (UMFPACK_ERROR_file_IO) ; \
+    } \
+}
+
+/* ========================================================================== */
+/* === UMFPACK_load_symbolic ================================================ */
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_load_symbolic
+(
+    void **SymbolicHandle,
+    char *user_filename
+)
+{
+    SymbolicType *Symbolic ;
+    char *filename ;
+    FILE *f ;
+
+    *SymbolicHandle = (void *) NULL ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get the filename, or use the default name if filename is NULL */
+    /* ---------------------------------------------------------------------- */
+
+    if (user_filename == (char *) NULL)
+    {
+       filename = "symbolic.umf" ;
+    }
+    else
+    {
+       filename = user_filename ;
+    }
+    f = fopen (filename, "rb") ;
+    if (!f)
+    {
+       return (UMFPACK_ERROR_file_IO) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* read the Symbolic header from the file, in binary */
+    /* ---------------------------------------------------------------------- */
+
+    Symbolic = (SymbolicType *) UMF_malloc (1, sizeof (SymbolicType)) ;
+    if (Symbolic == (SymbolicType *) NULL)
+    {
+       fclose (f) ;
+       return (UMFPACK_ERROR_out_of_memory) ;
+    }
+    if (fread (Symbolic, sizeof (SymbolicType), 1, f) != 1)
+    {
+       (void) UMF_free ((void *) Symbolic) ;
+       fclose (f) ;
+       return (UMFPACK_ERROR_file_IO) ;
+    }
+    if (ferror (f))
+    {
+       (void) UMF_free ((void *) Symbolic) ;
+       fclose (f) ;
+       return (UMFPACK_ERROR_file_IO) ;
+    }
+
+    if (Symbolic->valid != SYMBOLIC_VALID || Symbolic->n_row <= 0 ||
+       Symbolic->n_col <= 0 || Symbolic->nfr < 0 || Symbolic->nchains < 0 ||
+       Symbolic->esize < 0)
+    {
+       /* Symbolic does not point to a Symbolic object */
+       (void) UMF_free ((void *) Symbolic) ;
+       fclose (f) ;
+       return (UMFPACK_ERROR_invalid_Symbolic_object) ;
+    }
+
+    Symbolic->Cperm_init         = (Int *) NULL ;
+    Symbolic->Rperm_init         = (Int *) NULL ;
+    Symbolic->Front_npivcol      = (Int *) NULL ;
+    Symbolic->Front_parent       = (Int *) NULL ;
+    Symbolic->Front_1strow       = (Int *) NULL ;
+    Symbolic->Front_leftmostdesc = (Int *) NULL ;
+    Symbolic->Chain_start        = (Int *) NULL ;
+    Symbolic->Chain_maxrows      = (Int *) NULL ;
+    Symbolic->Chain_maxcols      = (Int *) NULL ;
+    Symbolic->Cdeg               = (Int *) NULL ;
+    Symbolic->Rdeg               = (Int *) NULL ;
+    Symbolic->Esize              = (Int *) NULL ;
+    Symbolic->Diagonal_map       = (Int *) NULL ;
+
+    /* umfpack_free_symbolic can now be safely called if an error occurs */
+
+    /* ---------------------------------------------------------------------- */
+    /* read the rest of the Symbolic object */
+    /* ---------------------------------------------------------------------- */
+
+    READ (Symbolic->Cperm_init,         Int, Symbolic->n_col+1) ;
+    READ (Symbolic->Rperm_init,         Int, Symbolic->n_row+1) ;
+    READ (Symbolic->Front_npivcol,      Int, Symbolic->nfr+1) ;
+    READ (Symbolic->Front_parent,       Int, Symbolic->nfr+1) ;
+    READ (Symbolic->Front_1strow,       Int, Symbolic->nfr+1) ;
+    READ (Symbolic->Front_leftmostdesc, Int, Symbolic->nfr+1) ;
+    READ (Symbolic->Chain_start,        Int, Symbolic->nchains+1) ;
+    READ (Symbolic->Chain_maxrows,      Int, Symbolic->nchains+1) ;
+    READ (Symbolic->Chain_maxcols,      Int, Symbolic->nchains+1) ;
+    READ (Symbolic->Cdeg,               Int, Symbolic->n_col+1) ;
+    READ (Symbolic->Rdeg,               Int, Symbolic->n_row+1) ;
+    if (Symbolic->esize > 0)
+    {
+       /* only when dense rows are present */
+       READ (Symbolic->Esize, Int, Symbolic->esize) ;
+    }
+    if (Symbolic->prefer_diagonal)
+    {
+       /* only when diagonal pivoting is prefered */
+       READ (Symbolic->Diagonal_map, Int, Symbolic->n_col+1) ;
+    }
+
+    /* close the file */
+    fclose (f) ;
+
+    /* make sure the Symbolic object is valid */
+    if (!UMF_valid_symbolic (Symbolic))
+    {
+       UMFPACK_free_symbolic ((void **) &Symbolic) ;
+       return (UMFPACK_ERROR_invalid_Symbolic_object) ;
+    }
+
+    *SymbolicHandle = (void *) Symbolic ;
+    return (UMFPACK_OK) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_numeric.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_numeric.c
new file mode 100644 (file)
index 0000000..9456d91
--- /dev/null
@@ -0,0 +1,796 @@
+/* ========================================================================== */
+/* === UMFPACK_numeric ====================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Factorizes A into its LU factors, given a symbolic
+    pre-analysis computed by UMFPACK_symbolic.  See umfpack_numeric.h for a
+    description.
+
+    Dynamic memory allocation:  substantial.  See comments (1) through (7),
+    below.  If an error occurs, all allocated space is free'd by UMF_free.
+    If successful, the Numeric object contains 11 to 13 objects allocated by
+    UMF_malloc that hold the LU factors of the input matrix.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_symbolic.h"
+#include "umf_set_stats.h"
+#include "umf_kernel.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+#include "umf_realloc.h"
+
+#ifndef NDEBUG
+PRIVATE Int init_count ;
+#endif
+
+PRIVATE Int work_alloc
+(
+    WorkType *Work,
+    SymbolicType *Symbolic
+) ;
+
+PRIVATE void free_work
+(
+    WorkType *Work
+) ;
+
+PRIVATE Int numeric_alloc
+(
+    NumericType **NumericHandle,
+    SymbolicType *Symbolic,
+    double alloc_init,
+    Int scale
+) ;
+
+PRIVATE void error
+(
+    NumericType **Numeric,
+    WorkType *Work
+) ;
+
+
+/* ========================================================================== */
+/* === UMFPACK_numeric ====================================================== */
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_numeric
+(
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const double Ax [ ],
+#ifdef COMPLEX
+    const double Az [ ],
+#endif
+    void *SymbolicHandle,
+    void **NumericHandle,
+    const double Control [UMFPACK_CONTROL],
+    double User_Info [UMFPACK_INFO]
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    NumericType *Numeric ;
+    SymbolicType *Symbolic ;
+    WorkType WorkSpace, *Work ;
+    Int n_row, n_col, n_inner, newsize, i, status, *inew, npiv, ulen, scale ;
+    Unit *mnew ;
+    double Info2 [UMFPACK_INFO], *Info, alloc_init, relpt, relpt2, droptol,
+       front_alloc_init, stats [2] ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get the amount of time used by the process so far */
+    /* ---------------------------------------------------------------------- */
+
+    umfpack_tic (stats) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* initialize and check inputs */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    UMF_dump_start ( ) ;
+    init_count = UMF_malloc_count ;
+    DEBUGm4 (("\nUMFPACK numeric: U transpose version\n")) ;
+#endif
+
+    /* If front_alloc_init negative then allocate that size of front in
+     * UMF_start_front.  If alloc_init negative, then allocate that initial
+     * size of Numeric->Memory. */
+
+    relpt = GET_CONTROL (UMFPACK_PIVOT_TOLERANCE,
+       UMFPACK_DEFAULT_PIVOT_TOLERANCE) ;
+    relpt2 = GET_CONTROL (UMFPACK_SYM_PIVOT_TOLERANCE,
+       UMFPACK_DEFAULT_SYM_PIVOT_TOLERANCE) ;
+    alloc_init = GET_CONTROL (UMFPACK_ALLOC_INIT, UMFPACK_DEFAULT_ALLOC_INIT) ;
+    front_alloc_init = GET_CONTROL (UMFPACK_FRONT_ALLOC_INIT,
+       UMFPACK_DEFAULT_FRONT_ALLOC_INIT) ;
+    scale = GET_CONTROL (UMFPACK_SCALE, UMFPACK_DEFAULT_SCALE) ;
+    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
+#ifdef COMPLEX
+       || !Az
+#endif
+    )
+    {
+       Info [UMFPACK_STATUS] = UMFPACK_ERROR_argument_missing ;
+       return (UMFPACK_ERROR_argument_missing) ;
+    }
+
+    Info [UMFPACK_NZ] = Ap [n_col] ;
+    *NumericHandle = (void *) NULL ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the Work object */
+    /* ---------------------------------------------------------------------- */
+
+    /* (1) calls UMF_malloc 15 or 17 times, to obtain temporary workspace of
+     * size c+1 Entry's and 2*(n_row+1) + 3*(n_col+1) + (n_col+n_inner+1) +
+     * (nn+1) + * 3*(c+1) + 2*(r+1) + max(r,c) + (nfr+1) integers plus 2*nn
+     * more integers if diagonal pivoting is to be done.  r is the maximum
+     * number of rows in any frontal matrix, c is the maximum number of columns
+     * in any frontal matrix, n_inner is min (n_row,n_col), nn is
+     * max (n_row,n_col), and nfr is the number of frontal matrices.  For a
+     * square matrix, this is c+1 Entry's and about 8n + 3c + 2r + max(r,c) +
+     * nfr integers, plus 2n more for diagonal pivoting.
+     */
+
+    Work = &WorkSpace ;
+    Work->n_row = n_row ;
+    Work->n_col = n_col ;
+    Work->nfr = Symbolic->nfr ;
+    Work->nb = Symbolic->nb ;
+    Work->n1 = Symbolic->n1 ;
+
+    if (!work_alloc (Work, Symbolic))
+    {
+       DEBUGm4 (("out of memory: numeric work\n")) ;
+       Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+       error (&Numeric, Work) ;
+       return (UMFPACK_ERROR_out_of_memory) ;
+    }
+    ASSERT (UMF_malloc_count == init_count + 16 + 2*Symbolic->prefer_diagonal) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate Numeric object */
+    /* ---------------------------------------------------------------------- */
+
+    /* (2) calls UMF_malloc 10 or 11 times, for a total space of
+     * sizeof (NumericType) bytes, 4*(n_row+1) + 4*(n_row+1) integers, and
+     * (n_inner+1) Entry's, plus n_row Entry's if row scaling is to be done.
+     * sizeof (NumericType) is a small constant.  Next, it calls UMF_malloc
+     * once, for the variable-sized part of the Numeric object
+     * (Numeric->Memory).  The size of this object is the larger of
+     * (Control [UMFPACK_ALLOC_INIT]) *  (the approximate upper bound computed
+     * by UMFPACK_symbolic), and the minimum required to start the numerical
+     * factorization.  * This request is reduced if it fails.
+     */
+
+    if (!numeric_alloc (&Numeric, Symbolic, alloc_init, scale))
+    {
+       DEBUGm4 (("out of memory: initial numeric\n")) ;
+       Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+       error (&Numeric, Work) ;
+       return (UMFPACK_ERROR_out_of_memory) ;
+    }
+    DEBUG0 (("malloc: init_count "ID" UMF_malloc_count "ID"\n",
+       init_count, UMF_malloc_count)) ;
+    ASSERT (UMF_malloc_count == init_count
+       + (16 + 2*Symbolic->prefer_diagonal)
+       + (11 + (scale != UMFPACK_SCALE_NONE))) ;
+
+    /* set control parameters */
+    Numeric->relpt = relpt ;
+    Numeric->relpt2 = relpt2 ;
+    Numeric->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
+)
+{
+    Int n_row, n_col, n_inner, min_usage, trying ;
+    NumericType *Numeric ;
+    double nsize, bsize ;
+
+    DEBUG0 (("numeric alloc:\n")) ;
+
+    n_row = Symbolic->n_row ;
+    n_col = Symbolic->n_col ;
+    n_inner = MIN (n_row, n_col) ;
+    *NumericHandle = (NumericType *) NULL ;
+
+    /* 1 allocation:  accounted for in UMF_set_stats (num_On_size1),
+     * free'd in umfpack_free_numeric */
+    Numeric = (NumericType *) UMF_malloc (1, sizeof (NumericType)) ;
+
+    if (!Numeric)
+    {
+       return (FALSE) ;        /* out of memory */
+    }
+    Numeric->valid = 0 ;
+    *NumericHandle = Numeric ;
+
+    /* 9 allocations:  accounted for in UMF_set_stats (num_On_size1),
+     * free'd in umfpack_free_numeric */
+    Numeric->D = (Entry *) UMF_malloc (n_inner+1, sizeof (Entry)) ;
+    Numeric->Rperm = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ;
+    Numeric->Cperm = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ;
+    Numeric->Lpos = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ;
+    Numeric->Lilen = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ;
+    Numeric->Lip = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ;
+    Numeric->Upos = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ;
+    Numeric->Uilen = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ;
+    Numeric->Uip = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ;
+
+    /* 1 allocation if scaling:  in UMF_set_stats (num_On_size1),
+     * free'd in umfpack_free_numeric */
+    if (scale != UMFPACK_SCALE_NONE)
+    {
+       DEBUG0 (("Allocating scale factors\n")) ;
+       Numeric->Rs = (double *) UMF_malloc (n_row, sizeof (double)) ;
+    }
+    else
+    {
+       DEBUG0 (("No scale factors allocated (R = I)\n")) ;
+       Numeric->Rs = (double *) NULL ;
+    }
+
+    Numeric->Memory = (Unit *) NULL ;
+
+    /* Upattern has already been allocated as part of the Work object.  If
+     * the matrix is singular or rectangular, and there are off-diagonal
+     * nonzeros in the last pivot row, then Work->Upattern is not free'd.
+     * Instead it is transfered to Numeric->Upattern.  If it exists,
+     * Numeric->Upattern is free'd in umfpack_free_numeric. */
+    Numeric->Upattern = (Int *) NULL ; /* used for singular matrices only */
+
+    if (!Numeric->D || !Numeric->Rperm || !Numeric->Cperm || !Numeric->Upos ||
+       !Numeric->Lpos || !Numeric->Lilen || !Numeric->Uilen || !Numeric->Lip ||
+       !Numeric->Uip || (scale != UMFPACK_SCALE_NONE && !Numeric->Rs))
+    {
+       return (FALSE) ;        /* out of memory */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate initial Numeric->Memory for LU factors and elements */
+    /* ---------------------------------------------------------------------- */
+
+    if (alloc_init < 0)
+    {
+       /* -alloc_init is the exact size to initially allocate */
+       nsize = -alloc_init ;
+    }
+    else
+    {
+       /* alloc_init is a ratio of the upper bound memory usage */
+       nsize = (alloc_init * Symbolic->num_mem_usage_est) + 1 ;
+    }
+    min_usage = Symbolic->num_mem_init_usage ;
+
+    /* Numeric->Memory must be large enough for UMF_kernel_init */
+    nsize = MAX (min_usage, nsize) ;
+
+    /* Numeric->Memory cannot be larger in size than Int_MAX / sizeof(Unit) */
+    /* For ILP32 mode:  2GB (nsize cannot be bigger than 256 Mwords) */
+    bsize = ((double) Int_MAX) / sizeof (Unit) - 1 ;
+    DEBUG0 (("bsize %g\n", bsize)) ;
+    nsize = MIN (nsize, bsize) ;
+
+    Numeric->size = (Int) nsize ;
+
+    DEBUG0 (("Num init %g usage_est %g numsize "ID" minusage "ID"\n",
+       alloc_init, Symbolic->num_mem_usage_est, Numeric->size, min_usage)) ;
+
+    /* allocates 1 object: */
+    /* keep trying until successful, or memory request is too small */
+    trying = TRUE ;
+    while (trying)
+    {
+       Numeric->Memory = (Unit *) UMF_malloc (Numeric->size, sizeof (Unit)) ;
+       if (Numeric->Memory)
+       {
+           DEBUG0 (("Successful Numeric->size: "ID"\n", Numeric->size)) ;
+           return (TRUE) ;
+       }
+       /* too much, reduce the request (but not below the minimum) */
+       /* and try again */
+       trying = Numeric->size > min_usage ;
+       Numeric->size = (Int)
+           (UMF_REALLOC_REDUCTION * ((double) Numeric->size)) ;
+       Numeric->size = MAX (min_usage, Numeric->size) ;
+    }
+
+    return (FALSE) ;   /* we failed to allocate Numeric->Memory */
+}
+
+
+/* ========================================================================== */
+/* === work_alloc =========================================================== */
+/* ========================================================================== */
+
+/* Allocate the Work object.  Return TRUE if successful. */
+
+PRIVATE Int work_alloc
+(
+    WorkType *Work,
+    SymbolicType *Symbolic
+)
+{
+    Int n_row, n_col, nn, maxnrows, maxncols, nfr, ok, maxnrc, n1 ;
+
+    n_row = Work->n_row ;
+    n_col = Work->n_col ;
+    nn = MAX (n_row, n_col) ;
+    nfr = Work->nfr ;
+    n1 = Symbolic->n1 ;
+    ASSERT (n1 <= n_row && n1 <= n_col) ;
+
+    maxnrows = Symbolic->maxnrows + Symbolic->nb ;
+    maxnrows = MIN (n_row, maxnrows) ;
+    maxncols = Symbolic->maxncols + Symbolic->nb ;
+    maxncols = MIN (n_col, maxncols) ;
+    maxnrc = MAX (maxnrows, maxncols) ;
+
+    DEBUG0 (("work alloc:  maxnrows+nb "ID" maxncols+nb "ID"\n",
+       maxnrows, maxncols)) ;
+
+    /* 15 allocations, freed in free_work: */
+    /* accounted for in UMF_set_stats (work_usage) */
+    Work->Wx = (Entry *) UMF_malloc (maxnrows + 1, sizeof (Entry)) ;
+    Work->Wy = (Entry *) UMF_malloc (maxnrows + 1, sizeof (Entry)) ;
+    Work->Frpos    = (Int *) UMF_malloc (n_row + 1, sizeof (Int)) ;
+    Work->Lpattern = (Int *) UMF_malloc (n_row + 1, sizeof (Int)) ;
+    Work->Fcpos = (Int *) UMF_malloc (n_col + 1, sizeof (Int)) ;
+    Work->Wp = (Int *) UMF_malloc (nn + 1, sizeof (Int)) ;
+    Work->Wrp = (Int *) UMF_malloc (MAX (n_col,maxnrows) + 1, sizeof (Int)) ;
+    Work->Frows = (Int *) UMF_malloc (maxnrows + 1, sizeof (Int)) ;
+    Work->Wm    = (Int *) UMF_malloc (maxnrows + 1, sizeof (Int)) ;
+    Work->Fcols = (Int *) UMF_malloc (maxncols + 1, sizeof (Int)) ;
+    Work->Wio   = (Int *) UMF_malloc (maxncols + 1, sizeof (Int)) ;
+    Work->Woi   = (Int *) UMF_malloc (maxncols + 1, sizeof (Int)) ;
+    Work->Woo = (Int *) UMF_malloc (maxnrc + 1, sizeof (Int));
+    Work->elen = (n_col - n1) + (n_row - n1) + MIN (n_col-n1, n_row-n1) + 1 ;
+    Work->E = (Int *) UMF_malloc (Work->elen, sizeof (Int)) ;
+    Work->Front_new1strow = (Int *) UMF_malloc (nfr + 1, sizeof (Int)) ;
+
+    ok = (Work->Frpos && Work->Fcpos && Work->Lpattern
+       && Work->Wp && Work->Wrp && Work->Frows && Work->Fcols
+       && Work->Wio && Work->Woi && Work->Woo && Work->Wm
+       && Work->E && Work->Front_new1strow && Work->Wx && Work->Wy) ;
+
+    /* 2 allocations: accounted for in UMF_set_stats (work_usage) */
+    if (Symbolic->prefer_diagonal)
+    {
+       Work->Diagonal_map  = (Int *) UMF_malloc (nn, sizeof (Int)) ;
+       Work->Diagonal_imap = (Int *) UMF_malloc (nn, sizeof (Int)) ;
+       ok = ok && Work->Diagonal_map && Work->Diagonal_imap ;
+    }
+    else
+    {
+       /* no diagonal map needed for rectangular matrices */
+       Work->Diagonal_map = (Int *) NULL ;
+       Work->Diagonal_imap = (Int *) NULL ;
+    }
+
+    /* 1 allocation, may become part of Numeric (if singular or rectangular): */
+    Work->Upattern = (Int *) UMF_malloc (n_col + 1, sizeof (Int)) ;
+    ok = ok && Work->Upattern ;
+
+    /* current frontal matrix does not yet exist */
+    Work->Flublock = (Entry *) NULL ;
+    Work->Flblock  = (Entry *) NULL ;
+    Work->Fublock  = (Entry *) NULL ;
+    Work->Fcblock  = (Entry *) NULL ;
+
+    DEBUG0 (("work alloc done.\n")) ;
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === free_work ============================================================ */
+/* ========================================================================== */
+
+PRIVATE void free_work
+(
+    WorkType *Work
+)
+{
+    DEBUG0 (("work free:\n")) ;
+    if (Work)
+    {
+       /* these 16 objects do exist */
+       Work->Wx = (Entry *) UMF_free ((void *) Work->Wx) ;
+       Work->Wy = (Entry *) UMF_free ((void *) Work->Wy) ;
+       Work->Frpos = (Int *) UMF_free ((void *) Work->Frpos) ;
+       Work->Fcpos = (Int *) UMF_free ((void *) Work->Fcpos) ;
+       Work->Lpattern = (Int *) UMF_free ((void *) Work->Lpattern) ;
+       Work->Upattern = (Int *) UMF_free ((void *) Work->Upattern) ;
+       Work->Wp = (Int *) UMF_free ((void *) Work->Wp) ;
+       Work->Wrp = (Int *) UMF_free ((void *) Work->Wrp) ;
+       Work->Frows = (Int *) UMF_free ((void *) Work->Frows) ;
+       Work->Fcols = (Int *) UMF_free ((void *) Work->Fcols) ;
+       Work->Wio = (Int *) UMF_free ((void *) Work->Wio) ;
+       Work->Woi = (Int *) UMF_free ((void *) Work->Woi) ;
+       Work->Woo = (Int *) UMF_free ((void *) Work->Woo) ;
+       Work->Wm = (Int *) UMF_free ((void *) Work->Wm) ;
+       Work->E = (Int *) UMF_free ((void *) Work->E) ;
+       Work->Front_new1strow =
+           (Int *) UMF_free ((void *) Work->Front_new1strow) ;
+
+       /* these objects might not exist */
+       Work->Diagonal_map = (Int *) UMF_free ((void *) Work->Diagonal_map) ;
+       Work->Diagonal_imap = (Int *) UMF_free ((void *) Work->Diagonal_imap) ;
+    }
+    DEBUG0 (("work free done.\n")) ;
+}
+
+
+/* ========================================================================== */
+/* === error ================================================================ */
+/* ========================================================================== */
+
+/* Error return from UMFPACK_numeric.  Free all allocated memory. */
+
+PRIVATE void error
+(
+    NumericType **Numeric,
+    WorkType *Work
+)
+{
+    free_work (Work) ;
+    UMFPACK_free_numeric ((void **) Numeric) ;
+    ASSERT (UMF_malloc_count == init_count) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_qsymbolic.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_qsymbolic.c
new file mode 100644 (file)
index 0000000..910a50c
--- /dev/null
@@ -0,0 +1,2366 @@
+/* ========================================================================== */
+/* === UMFPACK_qsymbolic ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Performs a symbolic factorization.
+    See umfpack_qsymbolic.h and umfpack_symbolic.h for details.
+
+    Dynamic memory usage:  about (3.4nz + 8n + n) integers and n double's as
+    workspace (via UMF_malloc, for a square matrix).  All of it is free'd via
+    UMF_free if an error occurs.  If successful, the Symbolic object contains
+    12 to 14 objects allocated by UMF_malloc, with a total size of no more
+    than about 13*n integers.
+*/
+
+#include "umf_internal.h"
+#include "umf_symbolic_usage.h"
+#include "umf_colamd.h"
+#include "umf_set_stats.h"
+#include "umf_analyze.h"
+#include "umf_transpose.h"
+#include "umf_is_permutation.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+#include "umf_2by2.h"
+#include "umf_singletons.h"
+
+typedef struct /* SWType */
+{
+    Int *Front_npivcol ;    /* size n_col + 1 */
+    Int *Front_nrows ;     /* size n_col */
+    Int *Front_ncols ;     /* size n_col */
+    Int *Front_parent ;            /* size n_col */
+    Int *Front_cols ;      /* size n_col */
+    Int *InFront ;         /* size n_row */
+    Int *Ci ;              /* size Clen */
+    Int *Cperm1 ;          /* size n_col */
+    Int *Rperm1 ;          /* size n_row */
+    Int *InvRperm1 ;       /* size n_row */
+    Int *Si ;              /* size nz */
+    Int *Sp ;              /* size n_col + 1 */
+    double *Rs ;           /* size n_row */
+    Int *Rperm_2by2 ;      /* size n_row */
+
+} SWType ;
+
+PRIVATE void free_work
+(
+    SWType *SW
+) ;
+
+PRIVATE void error
+(
+    SymbolicType **Symbolic,
+    SWType *SW
+) ;
+
+/* worst-case usage for SW object */
+#define SYM_WORK_USAGE(n_col,n_row,Clen) \
+    (DUNITS (Int, Clen) + \
+     DUNITS (Int, nz) + \
+     4 * DUNITS (Int, n_row) + \
+     4 * DUNITS (Int, n_col) + \
+     2 * DUNITS (Int, n_col + 1) + \
+     DUNITS (double, n_row))
+
+/* required size of Ci for code that calls UMF_transpose and UMF_analyze below*/
+#define UMF_ANALYZE_CLEN(nz,n_row,n_col,nn) \
+    ((n_col) + MAX ((nz),(n_col)) + 3*(nn)+1 + (n_col))
+
+/* size of an element (in Units), including tuples */
+#define ELEMENT_SIZE(r,c) \
+    (DGET_ELEMENT_SIZE (r, c) + 1 + (r + c) * UNITS (Tuple, 1))
+
+#ifndef NDEBUG
+PRIVATE Int init_count ;
+#endif
+
+/* ========================================================================== */
+/* === do_amd =============================================================== */
+/* ========================================================================== */
+
+PRIVATE void do_amd
+(
+    Int n,
+    const Int Ap [ ],          /* size n+1 */
+    const Int Ai [ ],          /* size nz = Ap [n] */
+    Int Q [ ],                 /* output permutation, j = Q [k] */
+    Int Qinv [ ],              /* output inverse permutation, Qinv [j] = k */
+    Int Sdeg [ ],              /* degree of A+A', from AMD_aat */
+    Int Clen,                  /* size of Ci */
+    Int Ci [ ],                        /* size Ci workspace */
+    double amd_Control [ ],    /* AMD control parameters */
+    double amd_Info [ ],       /* AMD info */
+    SymbolicType *Symbolic,    /* Symbolic object */
+    double Info [ ]            /* UMFPACK info */
+)
+{
+
+    if (n == 0)
+    {
+       Symbolic->amd_dmax = 0 ;
+       Symbolic->amd_lunz = 0 ;
+       Info [UMFPACK_SYMMETRIC_LUNZ] = 0 ;
+       Info [UMFPACK_SYMMETRIC_FLOPS] = 0 ;
+       Info [UMFPACK_SYMMETRIC_DMAX] = 0 ;
+       Info [UMFPACK_SYMMETRIC_NDENSE] = 0 ;
+    }
+    else
+    {
+       AMD_1 (n, Ap, Ai, Q, Qinv, Sdeg, Clen, Ci, amd_Control, amd_Info) ;
+
+       /* return estimates computed from AMD on PA+PA' */
+       Symbolic->amd_dmax = amd_Info [AMD_DMAX] ;
+       Symbolic->amd_lunz = 2 * amd_Info [AMD_LNZ] + n ;
+       Info [UMFPACK_SYMMETRIC_LUNZ] = Symbolic->amd_lunz ;
+       Info [UMFPACK_SYMMETRIC_FLOPS] = DIV_FLOPS * amd_Info [AMD_NDIV] +
+           MULTSUB_FLOPS * amd_Info [AMD_NMULTSUBS_LU] ;
+       Info [UMFPACK_SYMMETRIC_DMAX] = Symbolic->amd_dmax ;
+       Info [UMFPACK_SYMMETRIC_NDENSE] = amd_Info [AMD_NDENSE] ;
+       Info [UMFPACK_SYMBOLIC_DEFRAG] += amd_Info [AMD_NCMPA] ;
+    }
+}
+
+/* ========================================================================== */
+/* === prune_singletons ===================================================== */
+/* ========================================================================== */
+
+/* Create the submatrix after removing the n1 singletons.  The matrix has
+ * row and column indices in the range 0 to n_row-n1 and 0 to n_col-n1,
+ * respectively.  */
+
+PRIVATE Int prune_singletons
+(
+    Int n1,
+    Int n_col,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const double Ax [ ],
+#ifdef COMPLEX
+    const double Az [ ],
+#endif
+    Int Cperm1 [ ],
+    Int InvRperm1 [ ],
+    Int Si [ ],
+    Int Sp [ ]
+#ifndef NDEBUG
+    , Int Rperm1 [ ]
+    , Int n_row
+#endif
+)
+{
+    Int row, k, pp, p, oldcol, newcol, newrow, nzdiag, do_nzdiag ;
+
+    nzdiag = 0 ;
+    do_nzdiag = (Ax != (double *) NULL)
+#ifdef COMPLEX
+       && (Az != (double *) NULL)
+#endif
+       ;
+
+#ifndef NDEBUG
+    DEBUGm4 (("Prune : S = A (Cperm1 (n1+1:end), Rperm1 (n1+1:end))\n")) ;
+    for (k = 0 ; k < n_row ; k++)
+    {
+       ASSERT (Rperm1 [k] >= 0 && Rperm1 [k] < n_row) ;
+       ASSERT (InvRperm1 [Rperm1 [k]] == k) ;
+    }
+#endif
+
+    /* create the submatrix after removing singletons */
+
+    pp = 0 ;
+    for (k = n1 ; k < n_col ; k++)
+    {
+       oldcol = Cperm1 [k] ;
+       newcol = k - n1 ;
+       DEBUG5 (("Prune singletons k "ID" oldcol "ID" newcol "ID": "ID"\n",
+           k, oldcol, newcol, pp)) ;
+       Sp [newcol] = pp ;  /* load column pointers */
+       for (p = Ap [oldcol] ; p < Ap [oldcol+1] ; p++)
+       {
+           row = Ai [p] ;
+           DEBUG5 (("  "ID":  row "ID, pp, row)) ;
+           ASSERT (row >= 0 && row < n_row) ;
+           newrow = InvRperm1 [row] - n1 ;
+           ASSERT (newrow < n_row - n1) ;
+           if (newrow >= 0)
+           {
+               DEBUG5 (("  newrow "ID, newrow)) ;
+               Si [pp++] = newrow ;
+               if (do_nzdiag)
+               {
+                   /* count the number of truly nonzero entries on the
+                    * diagonal of S, excluding entries that are present,
+                    * but numerically zero */
+                   if (newrow == newcol)
+                   {
+                       /* this is the diagonal entry */
+                       if (SCALAR_IS_NONZERO (Ax [p])
+#ifdef COMPLEX
+                        || SCALAR_IS_NONZERO (Az [p])
+#endif
+                       )
+                       {
+                           nzdiag++ ;
+                       }
+                   }
+               }
+           }
+           DEBUG5 (("\n")) ;
+       }
+    }
+    Sp [n_col - n1] = pp ;
+
+    ASSERT (AMD_valid (n_row - n1, n_col - n1, Sp, Si)) ;
+    return (nzdiag) ;
+}
+
+/* ========================================================================== */
+/* === combine_ordering ===================================================== */
+/* ========================================================================== */
+
+PRIVATE void combine_ordering
+(
+    Int n1,
+    Int nempty_col,
+    Int n_col,
+    Int Cperm_init [ ],            /* output permutation */
+    Int Cperm1 [ ],        /* singleton and empty column ordering */
+    Int Qinv [ ]           /* Qinv from AMD or COLAMD */
+)
+{
+    Int k, oldcol, newcol, knew ;
+
+    /* combine the singleton ordering with Qinv */
+#ifndef NDEBUG
+    for (k = 0 ; k < n_col ; k++)
+    {
+       Cperm_init [k] = EMPTY ;
+    }
+#endif
+    for (k = 0 ; k < n1 ; k++)
+    {
+       DEBUG1 ((ID" Initial singleton: "ID"\n", k, Cperm1 [k])) ;
+       Cperm_init [k] = Cperm1 [k] ;
+    }
+    for (k = n1 ; k < n_col - nempty_col ; k++)
+    {
+       /* this is a non-singleton column */
+       oldcol = Cperm1 [k] ;   /* user's name for this column */
+       newcol = k - n1 ;       /* Qinv's name for this column */
+       knew = Qinv [newcol] ;  /* Qinv's ordering for this column */
+       knew += n1 ;            /* shift order, after singletons */
+       DEBUG1 ((" k "ID" oldcol "ID" newcol "ID" knew "ID"\n",
+           k, oldcol, newcol, knew)) ;
+       ASSERT (knew >= 0 && knew < n_col - nempty_col) ;
+       ASSERT (Cperm_init [knew] == EMPTY) ;
+       Cperm_init [knew] = oldcol ;
+    }
+    for (k = n_col - nempty_col ; k < n_col ; k++)
+    {
+       Cperm_init [k] = Cperm1 [k] ;
+    }
+#ifndef NDEBUG
+    {
+       Int *W = (Int *) malloc ((n_col + 1) * sizeof (Int)) ;
+       ASSERT (UMF_is_permutation (Cperm_init, W, n_col, n_col)) ;
+       free (W) ;
+    }
+#endif
+
+}
+
+/* ========================================================================== */
+/* === UMFPACK_qsymbolic ==================================================== */
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_qsymbolic
+(
+    Int n_row,
+    Int n_col,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const double Ax [ ],
+#ifdef COMPLEX
+    const double Az [ ],
+#endif
+    const Int Quser [ ],
+    void **SymbolicHandle,
+    const double Control [UMFPACK_CONTROL],
+    double User_Info [UMFPACK_INFO]
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int i, nz, j, newj, status, f1, f2, maxnrows, maxncols, nfr, col,
+       nchains, maxrows, maxcols, p, nb, nn, *Chain_start, *Chain_maxrows,
+       *Chain_maxcols, *Front_npivcol, *Ci, Clen, colamd_stats [COLAMD_STATS],
+       fpiv, n_inner, child, parent, *Link, row, *Front_parent,
+       analyze_compactions, k, chain, is_sym, *Si, *Sp, n2, do_UMF_analyze,
+       fpivcol, fallrows, fallcols, *InFront, *F1, snz, *Front_1strow, f1rows,
+       kk, *Cperm_init, *Rperm_init, newrow, *InvRperm1, *Front_leftmostdesc,
+       Clen_analyze, strategy, Clen_amd, fixQ, prefer_diagonal, nzdiag, nzaat,
+       *Wq, *Sdeg, *Fr_npivcol, nempty, *Fr_nrows, *Fr_ncols, *Fr_parent,
+       *Fr_cols, nempty_row, nempty_col, user_auto_strategy, fail, max_rdeg,
+       head_usage, tail_usage, lnz, unz, esize, *Esize, rdeg, *Cdeg, *Rdeg,
+       *Cperm1, *Rperm1, n1, oldcol, newcol, n1c, n1r, *Rperm_2by2, oldrow,
+       dense_row_threshold, tlen, aggressive ;
+    double knobs [COLAMD_KNOBS], flops, f, r, c, *Info, force_fixQ,
+       Info2 [UMFPACK_INFO], drow, dcol, dtail_usage, dlf, duf, dmax_usage,
+       dhead_usage, dlnz, dunz, dmaxfrsize, dClen, dClen_analyze, sym,
+       amd_Info [AMD_INFO], dClen_amd, dr, dc, cr, cc, cp,
+       amd_Control [AMD_CONTROL], stats [2], tol, scale ;
+    SymbolicType *Symbolic ;
+    SWType SWspace, *SW ;
+
+#ifndef NDEBUG
+    UMF_dump_start ( ) ;
+    init_count = UMF_malloc_count ;
+    PRINTF ((
+"**** Debugging enabled (UMFPACK will be exceedingly slow!) *****************\n"
+       )) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* get the amount of time used by the process so far */
+    /* ---------------------------------------------------------------------- */
+
+    umfpack_tic (stats) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get control settings and check input parameters */
+    /* ---------------------------------------------------------------------- */
+
+    drow = GET_CONTROL (UMFPACK_DENSE_ROW, UMFPACK_DEFAULT_DENSE_ROW) ;
+    dcol = GET_CONTROL (UMFPACK_DENSE_COL, UMFPACK_DEFAULT_DENSE_COL) ;
+    nb = GET_CONTROL (UMFPACK_BLOCK_SIZE, UMFPACK_DEFAULT_BLOCK_SIZE) ;
+    strategy = GET_CONTROL (UMFPACK_STRATEGY, UMFPACK_DEFAULT_STRATEGY) ;
+    tol = GET_CONTROL (UMFPACK_2BY2_TOLERANCE, UMFPACK_DEFAULT_2BY2_TOLERANCE) ;
+    scale = GET_CONTROL (UMFPACK_SCALE, UMFPACK_DEFAULT_SCALE) ;
+    force_fixQ = GET_CONTROL (UMFPACK_FIXQ, UMFPACK_DEFAULT_FIXQ) ;
+    AMD_defaults (amd_Control) ;
+    amd_Control [AMD_DENSE] =
+       GET_CONTROL (UMFPACK_AMD_DENSE, UMFPACK_DEFAULT_AMD_DENSE) ;
+    aggressive =
+       (GET_CONTROL (UMFPACK_AGGRESSIVE, UMFPACK_DEFAULT_AGGRESSIVE) != 0) ;
+    amd_Control [AMD_AGGRESSIVE] = aggressive ;
+
+    nb = MAX (2, nb) ;
+    nb = MIN (nb, MAXNB) ;
+    ASSERT (nb >= 0) ;
+    if (nb % 2 == 1) nb++ ;    /* make sure nb is even */
+    DEBUG0 (("UMFPACK_qsymbolic: nb = "ID" aggressive = "ID"\n", nb,
+       aggressive)) ;
+
+    tol = MAX (0.0, MIN (tol,  1.0)) ;
+    if (scale != UMFPACK_SCALE_NONE && scale != UMFPACK_SCALE_MAX)
+    {
+       scale = UMFPACK_DEFAULT_SCALE ;
+    }
+
+    if (User_Info != (double *) NULL)
+    {
+       /* return Info in user's array */
+       Info = User_Info ;
+    }
+    else
+    {
+       /* no Info array passed - use local one instead */
+       Info = Info2 ;
+    }
+    /* clear all of Info */
+    for (i = 0 ; i < UMFPACK_INFO ; i++)
+    {
+       Info [i] = EMPTY ;
+    }
+
+    nn = MAX (n_row, n_col) ;
+    n_inner = MIN (n_row, n_col) ;
+
+    Info [UMFPACK_STATUS] = UMFPACK_OK ;
+    Info [UMFPACK_NROW] = n_row ;
+    Info [UMFPACK_NCOL] = n_col ;
+    Info [UMFPACK_SIZE_OF_UNIT] = (double) (sizeof (Unit)) ;
+    Info [UMFPACK_SIZE_OF_INT] = (double) (sizeof (int)) ;
+    Info [UMFPACK_SIZE_OF_LONG] = (double) (sizeof (long)) ;
+    Info [UMFPACK_SIZE_OF_POINTER] = (double) (sizeof (void *)) ;
+    Info [UMFPACK_SIZE_OF_ENTRY] = (double) (sizeof (Entry)) ;
+    Info [UMFPACK_SYMBOLIC_DEFRAG] = 0 ;
+
+    if (!Ai || !Ap || !SymbolicHandle)
+    {
+       Info [UMFPACK_STATUS] = UMFPACK_ERROR_argument_missing ;
+       return (UMFPACK_ERROR_argument_missing) ;
+    }
+
+    *SymbolicHandle = (void *) NULL ;
+
+    if (n_row <= 0 || n_col <= 0)      /* n_row, n_col must be > 0 */
+    {
+       Info [UMFPACK_STATUS] = UMFPACK_ERROR_n_nonpositive ;
+       return (UMFPACK_ERROR_n_nonpositive) ;
+    }
+
+    nz = Ap [n_col] ;
+    DEBUG0 (("n_row "ID" n_col "ID" nz "ID"\n", n_row, n_col, nz)) ;
+    Info [UMFPACK_NZ] = nz ;
+    if (nz < 0)
+    {
+       Info [UMFPACK_STATUS] = UMFPACK_ERROR_invalid_matrix ;
+       return (UMFPACK_ERROR_invalid_matrix) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get the requested strategy */
+    /* ---------------------------------------------------------------------- */
+
+    if (n_row != n_col)
+    {
+       /* if the matrix is rectangular, the only available strategy is
+        *  unsymmetric */
+       strategy = UMFPACK_STRATEGY_UNSYMMETRIC ;
+       DEBUGm3 (("Rectangular: forcing unsymmetric strategy\n")) ;
+    }
+
+    if (strategy < UMFPACK_STRATEGY_AUTO
+     || strategy > UMFPACK_STRATEGY_SYMMETRIC)
+    {
+       /* unrecognized strategy */
+       strategy = UMFPACK_STRATEGY_AUTO ;
+    }
+
+    user_auto_strategy = (strategy == UMFPACK_STRATEGY_AUTO) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* determine amount of memory required for UMFPACK_symbolic */
+    /* ---------------------------------------------------------------------- */
+
+    /* The size of Clen required for UMF_colamd is always larger than */
+    /* UMF_analyze, but the max is included here in case that changes in */
+    /* future versions. */
+
+    /* This is about 2.2*nz + 9*n_col + 6*n_row, or nz/5 + 13*n_col + 6*n_row,
+     * whichever is bigger.  For square matrices, it works out to
+     * 2.2nz + 15n, or nz/5 + 19n, whichever is bigger (typically 2.2nz+15n). */
+    dClen = UMF_COLAMD_RECOMMENDED ((double) nz, (double) n_row,
+       (double) n_col) ;
+
+    /* This is defined above, as max (nz,n_col) + 3*nn+1 + 2*n_col, where
+     * nn = max (n_row,n_col).  It is always smaller than the space required
+     * for colamd or amd. */
+    dClen_analyze = UMF_ANALYZE_CLEN ((double) nz, (double) n_row,
+       (double) n_col, (double) nn) ;
+    dClen = MAX (dClen, dClen_analyze) ;
+
+    /* The space for AMD can be larger than what's required for colamd: */
+    dClen_amd = 2.4 * (double) nz + 8 * (double) n_inner ;
+    /* additional space for the 2-by-2 strategy */
+    dClen_amd += (double) MAX (nn, nz) ;
+    dClen = MAX (dClen, dClen_amd) ;
+
+    /* worst case total memory usage for UMFPACK_symbolic (revised below) */
+    Info [UMFPACK_SYMBOLIC_PEAK_MEMORY] =
+       SYM_WORK_USAGE (n_col, n_row, dClen) +
+       UMF_symbolic_usage (n_row, n_col, n_col, n_col, n_col, TRUE) ;
+
+    if (INT_OVERFLOW (dClen * sizeof (Int)))
+    {
+       /* :: int overflow, Clen too large :: */
+       /* Problem is too large for array indexing (Ci [i]) with an Int i. */
+       /* Cannot even analyze the problem to determine upper bounds on */
+       /* memory usage. Need to use the long integer version, umfpack_*l_*. */
+       DEBUGm4 (("out of memory: symbolic int overflow\n")) ;
+       Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+       return (UMFPACK_ERROR_out_of_memory) ;
+    }
+
+    /* repeat the size calculations, in integers */
+    Clen = UMF_COLAMD_RECOMMENDED (nz, n_row, n_col) ;
+    Clen_analyze = UMF_ANALYZE_CLEN (nz, n_row, n_col, nn) ;
+    Clen = MAX (Clen, Clen_analyze) ;
+    Clen_amd = 2.4 * nz + 8 * n_inner ;
+    Clen_amd += MAX (nn, nz) ;                 /* for Ri, in UMF_2by2 */
+    Clen = MAX (Clen, Clen_amd) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the first part of the Symbolic object (header and Cperm_init) */
+    /* ---------------------------------------------------------------------- */
+
+    /* (1) Five calls to UMF_malloc are made, for a total space of
+     * 2 * (n_row + n_col) + 4 integers + sizeof (SymbolicType).
+     * sizeof (SymbolicType) is a small constant.  This space is part of the
+     * Symbolic object and is not freed unless an error occurs.  If A is square
+     * then this is about 4*n integers.
+     */
+
+    Symbolic = (SymbolicType *) UMF_malloc (1, sizeof (SymbolicType)) ;
+
+    if (!Symbolic)
+    {
+       /* If we fail here, Symbolic is NULL and thus it won't be */
+       /* dereferenced by UMFPACK_free_symbolic, as called by error ( ). */
+       DEBUGm4 (("out of memory: symbolic object\n")) ;
+       Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+       error (&Symbolic, (SWType *) NULL) ;
+       return (UMFPACK_ERROR_out_of_memory) ;
+    }
+
+    /* We now know that Symbolic has been allocated */
+    Symbolic->valid = 0 ;
+    Symbolic->Chain_start = (Int *) NULL ;
+    Symbolic->Chain_maxrows = (Int *) NULL ;
+    Symbolic->Chain_maxcols = (Int *) NULL ;
+    Symbolic->Front_npivcol = (Int *) NULL ;
+    Symbolic->Front_parent = (Int *) NULL ;
+    Symbolic->Front_1strow = (Int *) NULL ;
+    Symbolic->Front_leftmostdesc = (Int *) NULL ;
+    Symbolic->Esize = (Int *) NULL ;
+    Symbolic->esize = 0 ;
+
+    Symbolic->Cperm_init   = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ;
+    Symbolic->Rperm_init   = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ;
+    Symbolic->Cdeg        = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ;
+    Symbolic->Rdeg        = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ;
+    Symbolic->Diagonal_map = (Int *) NULL ;
+
+    Cperm_init = Symbolic->Cperm_init ;
+    Rperm_init = Symbolic->Rperm_init ;
+    Cdeg = Symbolic->Cdeg ;
+    Rdeg = Symbolic->Rdeg ;
+
+    if (!Cperm_init || !Rperm_init || !Cdeg || !Rdeg)
+    {
+       DEBUGm4 (("out of memory: symbolic perm\n")) ;
+       Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+       error (&Symbolic, (SWType *) NULL) ;
+       return (UMFPACK_ERROR_out_of_memory) ;
+    }
+
+    Symbolic->n_row = n_row ;
+    Symbolic->n_col = n_col ;
+    Symbolic->nz = nz ;
+    Symbolic->nb = nb ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check user's input permutation */
+    /* ---------------------------------------------------------------------- */
+
+    if (Quser != (Int *) NULL)
+    {
+       /* use Cperm_init as workspace to check input permutation */
+       if (!UMF_is_permutation (Quser, Cperm_init, n_col, n_col))
+       {
+           Info [UMFPACK_STATUS] = UMFPACK_ERROR_invalid_permutation ;
+           error (&Symbolic, (SWType *) NULL) ;
+           return (UMFPACK_ERROR_invalid_permutation) ;
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* (2) Eleven calls to UMF_malloc are made, for workspace of size
+     * Clen + nz + 7*n_col + 2*n_row + 2 integers.  Clen is the larger of
+     *     MAX (2*nz, 4*n_col) + 8*n_col + 6*n_row + n_col + nz/5 and
+     *     2.4*nz + 8 * MIN (n_row, n_col) + MAX (n_row, n_col, nz)
+     * If A is square and non-singular, then Clen is
+     *     MAX (MAX (2*nz, 4*n) + 7*n + nz/5,  3.4*nz) + 8*n
+     * If A has at least 4*n nonzeros then Clen is
+     *     MAX (2.2*nz + 7*n,  3.4*nz) + 8*n
+     * If A has at least (7/1.2)*n nonzeros, (about 5.8*n), then Clen is
+     *     3.4*nz + 8*n
+     * This space will be free'd when this routine finishes.
+     *
+     * Total space thus far is about 3.4nz + 12n integers.
+     * For the double precision, 32-bit integer version, the user's matrix
+     * requires an equivalent space of 3*nz + n integers.  So this space is just
+     * slightly larger than the user's input matrix (including the numerical
+     * values themselves).
+     */
+
+    SW = &SWspace ;    /* used for UMFPACK_symbolic only */
+
+    /* Note that SW->Front_* does not include the dummy placeholder front. */
+    /* This space is accounted for by the SYM_WORK_USAGE macro. */
+
+    /* this is free'd early */
+    SW->Si           = (Int *) UMF_malloc (nz, sizeof (Int)) ;
+    SW->Sp           = (Int *) UMF_malloc (n_col + 1, sizeof (Int)) ;
+    SW->InvRperm1     = (Int *) UMF_malloc (n_row, sizeof (Int)) ;
+    SW->Cperm1       = (Int *) UMF_malloc (n_col, sizeof (Int)) ;
+
+    /* this is free'd late */
+    SW->Ci           = (Int *) UMF_malloc (Clen, sizeof (Int)) ;
+    SW->Front_npivcol = (Int *) UMF_malloc (n_col + 1, sizeof (Int)) ;
+    SW->Front_nrows   = (Int *) UMF_malloc (n_col, sizeof (Int)) ;
+    SW->Front_ncols   = (Int *) UMF_malloc (n_col, sizeof (Int)) ;
+    SW->Front_parent  = (Int *) UMF_malloc (n_col, sizeof (Int)) ;
+    SW->Front_cols    = (Int *) UMF_malloc (n_col, sizeof (Int)) ;
+    SW->Rperm1       = (Int *) UMF_malloc (n_row, sizeof (Int)) ;
+    SW->InFront              = (Int *) UMF_malloc (n_row, sizeof (Int)) ;
+
+    /* this is allocated later, and free'd after Cperm1 but before Ci */
+    SW->Rperm_2by2    = (Int *) NULL ;   /* will be nn Int's */
+
+    /* this is allocated last, and free'd first */
+    SW->Rs           = (double *) NULL ;       /* will be n_row double's */
+
+    Ci        = SW->Ci ;
+    Fr_npivcol = SW->Front_npivcol ;
+    Fr_nrows   = SW->Front_nrows ;
+    Fr_ncols   = SW->Front_ncols ;
+    Fr_parent  = SW->Front_parent ;
+    Fr_cols    = SW->Front_cols ;
+    Cperm1     = SW->Cperm1 ;
+    Rperm1     = SW->Rperm1 ;
+    Si        = SW->Si ;
+    Sp        = SW->Sp ;
+    InvRperm1  = SW->InvRperm1 ;
+    Rperm_2by2 = (Int *) NULL ;
+    InFront    = SW->InFront ;
+
+    if (!Ci || !Fr_npivcol || !Fr_nrows || !Fr_ncols || !Fr_parent || !Fr_cols
+       || !Cperm1 || !Rperm1 || !Si || !Sp || !InvRperm1 || !InFront)
+    {
+       DEBUGm4 (("out of memory: symbolic work\n")) ;
+       Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+       error (&Symbolic, SW) ;
+       return (UMFPACK_ERROR_out_of_memory) ;
+    }
+
+    DEBUG0 (("Symbolic UMF_malloc_count - init_count = "ID"\n",
+       UMF_malloc_count - init_count)) ;
+    ASSERT (UMF_malloc_count == init_count + 17) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* find the row and column singletons */
+    /* ---------------------------------------------------------------------- */
+
+    /* [ use first nz + n_row + MAX (n_row, n_col) entries in Ci as workspace,
+     * and use Rperm_init as workspace */
+    ASSERT (Clen >= nz + n_row + MAX (n_row, n_col)) ;
+
+    status = UMF_singletons (n_row, n_col, Ap, Ai, Quser, Cdeg, Cperm1, Rdeg,
+       Rperm1, InvRperm1, &n1, &n1c, &n1r, &nempty_col, &nempty_row, &is_sym,
+       &max_rdeg, /* workspace: */ Rperm_init, Ci, Ci + nz, Ci + nz + n_row) ;
+
+    /* ] done using Rperm_init and Ci as workspace */
+
+    /* InvRperm1 is now the inverse of Rperm1 */
+
+    if (status != UMFPACK_OK)
+    {
+       DEBUGm4 (("matrix invalid: UMF_singletons\n")) ;
+       Info [UMFPACK_STATUS] = status ;
+       error (&Symbolic, SW) ;
+       return (status) ;
+    }
+    Info [UMFPACK_NEMPTY_COL] = nempty_col ;
+    Info [UMFPACK_NEMPTY_ROW] = nempty_row ;
+    Info [UMFPACK_NDENSE_COL] = 0 ;    /* # dense rows/cols recomputed below */
+    Info [UMFPACK_NDENSE_ROW] = 0 ;
+    Info [UMFPACK_COL_SINGLETONS] = n1c ;
+    Info [UMFPACK_ROW_SINGLETONS] = n1r ;
+    Info [UMFPACK_S_SYMMETRIC] = is_sym ;
+
+    nempty = MIN (nempty_col, nempty_row) ;
+    Symbolic->nempty_row = nempty_row ;
+    Symbolic->nempty_col = nempty_col ;
+
+    /* UMF_singletons has verified that the user's input matrix is valid */
+    ASSERT (AMD_valid (n_row, n_col, Ap, Ai)) ;
+
+    Symbolic->n1 = n1 ;
+    Symbolic->nempty = nempty ;
+    ASSERT (n1 <= n_inner) ;
+    n2 = nn - n1 - nempty ;
+
+    dense_row_threshold =
+       UMFPACK_DENSE_DEGREE_THRESHOLD (drow, n_col - n1 - nempty_col) ;
+    Symbolic->dense_row_threshold = dense_row_threshold ;
+
+    if (!is_sym)
+    {
+       /* either the pruned submatrix rectangular, or it is square and
+        * Rperm [n1 .. n-nempty-1] is not the same as Cperm [n1 .. n-nempty-1].
+        * For the auto strategy, switch to the unsymmetric strategy.
+        * Otherwise, if the strategy selected by the user is symmetric or
+        * 2-by-2, then the singletons will be discarded. */
+       strategy = UMFPACK_STRATEGY_UNSYMMETRIC ;
+       DEBUGm4 (("Strategy: Unsymmetric singletons\n")) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* determine symmetry, nzdiag, and degrees of S+S' */
+    /* ---------------------------------------------------------------------- */
+
+    /* S is the matrix obtained after removing singletons
+     *   = A (Cperm1 [n1..n_col-nempty_col-1], Rperm1 [n1..n_row-nempty_row-1])
+     */
+
+    Wq = Rperm_init ;      /* use Rperm_init as workspace for Wq [ */
+    Sdeg = Cperm_init ;            /* use Cperm_init as workspace for Sdeg [ */
+    sym = EMPTY ;
+    nzaat = EMPTY ;
+    nzdiag = EMPTY ;
+    for (i = 0 ; i < AMD_INFO ; i++)
+    {
+       amd_Info [i] = EMPTY ;
+    }
+
+    if (strategy != UMFPACK_STRATEGY_UNSYMMETRIC)
+    {
+       /* This also determines the degree of each node in S+S' (Sdeg), which
+        * is needed by the 2-by-2 strategy, the symmetry of S, and the number
+        * of nonzeros on the diagonal of S. */
+       ASSERT (n_row == n_col) ;
+       ASSERT (nempty_row == nempty_col) ;
+
+       /* get the count of nonzeros on the diagonal of S, excluding explicitly
+        * zero entries.  nzdiag = amd_Info [AMD_NZDIAG] counts the zero entries
+        * in S. */
+
+       nzdiag = prune_singletons (n1, nn, Ap, Ai, Ax,
+#ifdef COMPLEX
+           Az,
+#endif
+           Cperm1, InvRperm1, Si, Sp
+#ifndef NDEBUG
+           , Rperm1, nn
+#endif
+           ) ;
+       nzaat = AMD_aat (n2, Sp, Si, Sdeg, Wq, amd_Info) ;
+       sym = amd_Info [AMD_SYMMETRY] ;
+       Info [UMFPACK_N2] = n2 ;
+       /* nzdiag = amd_Info [AMD_NZDIAG] counts the zero entries of S too */
+
+#ifndef NDEBUG
+       for (k = 0 ; k < n2 ; k++)
+       {
+           ASSERT (Sdeg [k] >= 0 && Sdeg [k] < n2) ;
+       }
+       ASSERT (Sp [n2] - n2 <= nzaat && nzaat <= 2 * Sp [n2]) ;
+       DEBUG0 (("Explicit zeros: "ID" %g\n", nzdiag, amd_Info [AMD_NZDIAG])) ;
+#endif
+    }
+
+    /* get statistics from amd_aat, if computed */
+    Symbolic->sym = sym ;
+    Symbolic->nzaat = nzaat ;
+    Symbolic->nzdiag = nzdiag ;
+    Symbolic->amd_dmax = EMPTY ;
+
+    Info [UMFPACK_PATTERN_SYMMETRY] = sym ;
+    Info [UMFPACK_NZ_A_PLUS_AT] = nzaat ;
+    Info [UMFPACK_NZDIAG] = nzdiag ;
+
+    /* ---------------------------------------------------------------------- */
+    /* determine the initial strategy based on symmetry and nnz (diag (S)) */
+    /* ---------------------------------------------------------------------- */
+
+    if (strategy == UMFPACK_STRATEGY_AUTO)
+    {
+       if (sym < 0.10)
+       {
+           /* highly unsymmetric: use the unsymmetric strategy */
+           strategy = UMFPACK_STRATEGY_UNSYMMETRIC ;
+           DEBUGm4 (("Strategy: select unsymmetric\n")) ;
+       }
+       else if (sym >= 0.7 && nzdiag == n2)
+       {
+           /* mostly symmetric, zero-free diagonal: use symmetric strategy */
+           strategy = UMFPACK_STRATEGY_SYMMETRIC ;
+           DEBUGm4 (("Strategy: select symmetric\n")) ;
+       }
+       else
+       {
+           /* Evaluate the symmetric 2-by-2 strategy, and select it, or
+            * the unsymmetric strategy if the 2-by-2 strategy doesn't look
+            * promising. */
+           strategy = UMFPACK_STRATEGY_2BY2 ;
+           DEBUGm4 (("Strategy: try 2-by-2\n")) ;
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* try the 2-by-2 strategy */
+    /* ---------------------------------------------------------------------- */
+
+    /* (3) If the 2-by-2 strategy is attempted, additional workspace of size
+     * nn integers and nn double's is allocated, where nn = n_row = n_col.
+     * The real workspace is immediately free'd.  The integer workspace of
+     * size nn remains until the end of umfpack_qsymbolic. */
+
+    /* If the resulting matrix S (Rperm_2by2, :) is too unsymmetric, then the
+     * unsymmetric strategy will be used instead. */
+
+    if (strategy == UMFPACK_STRATEGY_2BY2)
+    {
+       Int *Rp, *Ri, *Blen, *W, nz_papat, nzd2, nweak, unmatched,
+           Clen3 ;
+       double sym2 ;
+
+       /* ------------------------------------------------------------------ */
+       /* get workspace for UMF_2by2 */
+       /* ------------------------------------------------------------------ */
+
+       ASSERT (n_row == n_col && nn == n_row) ;
+
+#ifndef NDEBUG
+       for (k = 0 ; k < n2 ; k++)
+       {
+           ASSERT (Sdeg [k] >= 0 && Sdeg [k] < n2) ;
+       }
+#endif
+
+       /* allocate Rperm_2by2 */
+       SW->Rperm_2by2 = (Int *) UMF_malloc (nn, sizeof (Int)) ;
+       Rperm_2by2 = SW->Rperm_2by2 ;
+       if (Rperm_2by2 == (Int *) NULL)
+       {
+           DEBUGm4 (("out of memory: Rperm_2by2\n")) ;
+           Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+           error (&Symbolic, SW) ;
+           return (UMFPACK_ERROR_out_of_memory) ;
+       }
+
+       /* allocate Ri from the tail end of Ci [ */
+       Clen3 = Clen - (MAX (nn, nz) + 1) ;
+       Ri = Ci + Clen3 ;
+       ASSERT (Clen3 >= nz) ;  /* space required for UMF_2by2 */
+
+       /* use Fr_* as workspace for Rp, Blen, and W [ */
+       Rp = Fr_npivcol ;
+       Blen = Fr_ncols ;
+       W = Fr_cols ;
+
+       if (scale != UMFPACK_SCALE_NONE)
+       {
+           SW->Rs = (double *) UMF_malloc (nn, sizeof (double)) ;
+           if (SW->Rs == (double *) NULL)
+           {
+               DEBUGm4 (("out of memory: scale factors for 2-by-2\n")) ;
+               Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+               error (&Symbolic, SW) ;
+               return (UMFPACK_ERROR_out_of_memory) ;
+           }
+       }
+
+       /* ------------------------------------------------------------------ */
+       /* find the 2-by-2 row permutation */
+       /* ------------------------------------------------------------------ */
+
+       /* find a row permutation Rperm_2by2 such that S (Rperm_2by2, :)
+        * has a healthy diagonal */
+
+       UMF_2by2 (nn, Ap, Ai, Ax,
+#ifdef COMPLEX
+               Az,
+#endif
+               tol, scale, Cperm1,
+#ifndef NDEBUG
+               Rperm1,
+#endif
+               InvRperm1, n1, nempty, Sdeg, Rperm_2by2, &nweak, &unmatched,
+               Ri, Rp, SW->Rs, Blen, W, Ci, Wq) ;
+       DEBUGm3 (("2by2: nweak "ID" unmatched "ID"\n", nweak, unmatched)) ;
+       Info [UMFPACK_2BY2_NWEAK] = nweak ;
+       Info [UMFPACK_2BY2_UNMATCHED] = unmatched ;
+
+       SW->Rs = (double *) UMF_free ((void *) SW->Rs) ;
+
+       /* R = S (Rperm_2by2,:)' */
+       (void) UMF_transpose (n2, n2, Sp, Si, (double *) NULL, Rperm_2by2,
+           (Int *) NULL, 0, Rp, Ri, (double *) NULL, W, FALSE
+#ifdef COMPLEX
+           , (double *) NULL, (double *) NULL, FALSE
+#endif
+           ) ;
+       ASSERT (AMD_valid (n2, n2, Rp, Ri)) ;
+
+       /* contents of Si and Sp no longer needed, but the space is
+        * still needed */
+
+       /* ------------------------------------------------------------------ */
+       /* find symmetry of S (Rperm_2by2, :)', and prepare to order with AMD */
+       /* ------------------------------------------------------------------ */
+
+       for (i = 0 ; i < AMD_INFO ; i++)
+       {
+           amd_Info [i] = EMPTY ;
+       }
+       nz_papat = AMD_aat (n2, Rp, Ri, Sdeg, Wq, amd_Info) ;
+       sym2 = amd_Info [AMD_SYMMETRY] ;
+       nzd2 = amd_Info [AMD_NZDIAG] ;
+
+       Info [UMFPACK_2BY2_PATTERN_SYMMETRY] = sym2 ;
+       Info [UMFPACK_2BY2_NZ_PA_PLUS_PAT] = nz_papat ;
+       Info [UMFPACK_2BY2_NZDIAG] = nzd2 ;
+
+       DEBUG0 (("2by2: sym2 %g nzd2 "ID" n2 "ID"\n", sym2, nzd2, n2)) ;
+
+       /* ------------------------------------------------------------------ */
+       /* evaluate the 2-by-2 results */
+       /* ------------------------------------------------------------------ */
+
+       if (user_auto_strategy)
+       {
+           if ((sym2 > 1.1 * sym) && (nzd2 > 0.9 * n2))
+           {
+               /* 2-by-2 made it much more symmetric */
+               DEBUGm4 (("eval Strategy 2by2: much more symmetric:  2by2\n")) ;
+               strategy = UMFPACK_STRATEGY_2BY2 ;
+           }
+           else if (sym2 < 0.7 * sym)
+           {
+               /* 2-by-2 made it much more unsymmetric */
+               DEBUGm4 (("eval Strategy 2by2: much more UNsymmetric:unsym\n"));
+               strategy = UMFPACK_STRATEGY_UNSYMMETRIC ;
+           }
+           else if (sym2 < 0.25)
+           {
+               DEBUGm4 (("eval Strategy 2by2: is UNsymmetric: unsym\n"));
+               strategy = UMFPACK_STRATEGY_UNSYMMETRIC ;
+           }
+           else if (sym2 >= 0.51)
+           {
+               DEBUGm4 (("eval Strategy 2by2: sym2 >= 0.51: 2by2\n")) ;
+               strategy = UMFPACK_STRATEGY_2BY2 ;
+           }
+           else if (sym2 >= 0.999 * sym)
+           {
+               /* 2-by-2 improved symmetry, or made it only slightly worse */
+               DEBUGm4 (("eval Strategy 2by2: sym2 >= 0.999 sym: 2by2\n")) ;
+               strategy = UMFPACK_STRATEGY_2BY2 ;
+           }
+           else
+           {
+               /* can't decide what to do, so pick the unsymmetric strategy */
+               DEBUGm4 (("eval Strategy 2by2: punt: unsym\n"));
+               strategy = UMFPACK_STRATEGY_UNSYMMETRIC ;
+           }
+       }
+
+       /* ------------------------------------------------------------------ */
+       /* if the 2-by-2 strategy is selected: */
+       /* ------------------------------------------------------------------ */
+
+       if (strategy == UMFPACK_STRATEGY_2BY2)
+       {
+           if (Quser == (Int *) NULL)
+           {
+               /* 2-by-2 strategy is successful */
+               /* compute amd (S) */
+               Int *Qinv = Fr_npivcol ;
+               ASSERT (Clen3 >= (nz_papat + nz_papat/5 + nn) + 7*nn) ;
+               do_amd (n2, Rp, Ri, Wq, Qinv, Sdeg, Clen3, Ci,
+                   amd_Control, amd_Info, Symbolic, Info) ;
+               /* combine the singleton ordering and the AMD ordering */
+               combine_ordering (n1, nempty, nn, Cperm_init, Cperm1, Qinv) ;
+           }
+           /* fix Rperm_2by2 to reflect A, not S */
+           for (k = 0 ; k < n1 ; k++)
+           {
+               oldcol = Cperm1 [k] ;
+               i = k ;
+               oldrow = Rperm1 [k] ;
+               W [oldcol] = oldrow ;
+           }
+           for (k = n1 ; k < nn - nempty ; k++)
+           {
+               oldcol = Cperm1 [k] ;
+               i = Rperm_2by2 [k - n1] + n1 ;
+               oldrow = Rperm1 [i] ;
+               W [oldcol] = oldrow ;
+           }
+           for (k = nn - nempty ; k < nn ; k++)
+           {
+               oldcol = Cperm1 [k] ;
+               i = k ;
+               oldrow = Rperm1 [k] ;
+               W [oldcol] = oldrow ;
+           }
+           for (k = 0 ; k < nn ; k++)
+           {
+               Rperm_2by2 [k] = W [k] ;
+           }
+
+           /* Now, the "diagonal" entry in oldcol (where oldcol is the user's
+            * name for a column, is the entry in row oldrow (where oldrow is
+            * the user's name for a row, and oldrow = Rperm_2by2 [oldcol] */
+       }
+
+       /* Fr_* no longer needed for Rp, Blen, W ] */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* finalize the strategy, including fixQ and prefer_diagonal */
+    /* ---------------------------------------------------------------------- */
+
+    if (strategy == UMFPACK_STRATEGY_SYMMETRIC)
+    {
+       /* use given Quser or AMD (A+A'), fix Q during factorization,
+        * prefer diagonal */
+       DEBUG0 (("\nStrategy: symmetric\n")) ;
+       ASSERT (n_row == n_col) ;
+       Symbolic->ordering = UMFPACK_ORDERING_AMD ;
+       fixQ = TRUE ;
+       prefer_diagonal = TRUE ;
+    }
+    else if (strategy == UMFPACK_STRATEGY_2BY2)
+    {
+       /* use Q = given Quser or Q = AMD (PA+PA'), fix Q during factorization,
+        * prefer diagonal, and factorize PAQ, where P is found by UMF_2by2. */
+       DEBUG0 (("\nStrategy: symmetric 2-by-2\n")) ;
+       ASSERT (n_row == n_col) ;
+       Symbolic->ordering = UMFPACK_ORDERING_AMD ;
+       fixQ = TRUE ;
+       prefer_diagonal = TRUE ;
+    }
+    else
+    {
+       /* use given Quser or COLAMD (A), refine Q during factorization,
+        * no diagonal preference */
+       ASSERT (strategy == UMFPACK_STRATEGY_UNSYMMETRIC) ;
+       DEBUG0 (("\nStrategy: unsymmetric\n")) ;
+       Symbolic->ordering = UMFPACK_ORDERING_COLAMD ;
+       fixQ = FALSE ;
+       prefer_diagonal = FALSE ;
+    }
+
+    if (Quser != (Int *) NULL)
+    {
+       Symbolic->ordering = UMFPACK_ORDERING_GIVEN ;
+    }
+
+    if (force_fixQ > 0)
+    {
+       fixQ = TRUE ;
+       DEBUG0 (("Force fixQ true\n")) ;
+    }
+    else if (force_fixQ < 0)
+    {
+       fixQ = FALSE ;
+       DEBUG0 (("Force fixQ false\n")) ;
+    }
+
+    DEBUG0 (("Strategy: ordering:   "ID"\n", Symbolic->ordering)) ;
+    DEBUG0 (("Strategy: fixQ:       "ID"\n", fixQ)) ;
+    DEBUG0 (("Strategy: prefer diag "ID"\n", prefer_diagonal)) ;
+
+    /* get statistics from amd_aat, if computed */
+    Symbolic->strategy = strategy ;
+    Symbolic->fixQ = fixQ ;
+    Symbolic->prefer_diagonal = prefer_diagonal ;
+
+    Info [UMFPACK_STRATEGY_USED] = strategy ;
+    Info [UMFPACK_ORDERING_USED] = Symbolic->ordering ;
+    Info [UMFPACK_QFIXED] = fixQ ;
+    Info [UMFPACK_DIAG_PREFERRED] = prefer_diagonal ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get the AMD ordering for the symmetric strategy */
+    /* ---------------------------------------------------------------------- */
+
+    if (strategy == UMFPACK_STRATEGY_SYMMETRIC && Quser == (Int *) NULL)
+    {
+       /* symmetric strategy for a matrix with mostly symmetric pattern */
+       Int *Qinv = Fr_npivcol ;
+       ASSERT (n_row == n_col && nn == n_row) ;
+       ASSERT (Clen >= (nzaat + nzaat/5 + nn) + 7*nn) ;
+       do_amd (n2, Sp, Si, Wq, Qinv, Sdeg, Clen, Ci,
+               amd_Control, amd_Info, Symbolic, Info) ;
+       /* combine the singleton ordering and the AMD ordering */
+       combine_ordering (n1, nempty, nn, Cperm_init, Cperm1, Qinv) ;
+    }
+    /* Sdeg no longer needed ] */
+    /* done using Rperm_init as workspace for Wq ] */
+
+    /* Contents of Si and Sp no longer needed, but the space is still needed */
+
+    /* ---------------------------------------------------------------------- */
+    /* use the user's input column ordering (already in Cperm1) */
+    /* ---------------------------------------------------------------------- */
+
+    if (Quser != (Int *) NULL)
+    {
+       for (k = 0 ; k < n_col ; k++)
+       {
+           Cperm_init [k] = Cperm1 [k] ;
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* use COLAMD to order the matrix */
+    /* ---------------------------------------------------------------------- */
+
+    if (strategy == UMFPACK_STRATEGY_UNSYMMETRIC && Quser == (Int *) NULL)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* copy the matrix into colamd workspace (colamd destroys its input) */
+       /* ------------------------------------------------------------------ */
+
+       /* C = A (Cperm1 (n1+1:end), Rperm1 (n1+1:end)), where Ci is used as
+        * the row indices and Cperm_init (on input) is used as the column
+        * pointers. */
+
+       (void) prune_singletons (n1, n_col, Ap, Ai,
+           (double *) NULL,
+#ifdef COMPLEX
+           (double *) NULL,
+#endif
+           Cperm1, InvRperm1, Ci, Cperm_init
+#ifndef NDEBUG
+           , Rperm1, n_row
+#endif
+           ) ;
+
+       /* ------------------------------------------------------------------ */
+       /* set UMF_colamd defaults */
+       /* ------------------------------------------------------------------ */
+
+       UMF_colamd_set_defaults (knobs) ;
+       knobs [COLAMD_DENSE_ROW] = drow ;
+       knobs [COLAMD_DENSE_COL] = dcol ;
+       knobs [COLAMD_AGGRESSIVE] = aggressive ;
+
+       /* ------------------------------------------------------------------ */
+       /* check input matrix and find the initial column pre-ordering */
+       /* ------------------------------------------------------------------ */
+
+       /* NOTE: umf_colamd is not given any original empty rows or columns.
+        * Those have already been removed via prune_singletons, above.  The
+        * umf_colamd routine has been modified to assume that all rows and
+        * columns have at least one entry in them.  It will break if it is
+        * given empty rows or columns (an assertion is triggered when running
+        * in debug mode. */
+
+       (void) UMF_colamd (
+               n_row - n1 - nempty_row,
+               n_col - n1 - nempty_col,
+               Clen, Ci, Cperm_init, knobs, colamd_stats,
+               Fr_npivcol, Fr_nrows, Fr_ncols, Fr_parent, Fr_cols, &nfr,
+               InFront) ;
+       ASSERT (colamd_stats [COLAMD_EMPTY_ROW] == 0) ;
+       ASSERT (colamd_stats [COLAMD_EMPTY_COL] == 0) ;
+
+       /* # of dense rows will be recomputed below */
+       Info [UMFPACK_NDENSE_ROW]  = colamd_stats [COLAMD_DENSE_ROW] ;
+       Info [UMFPACK_NDENSE_COL]  = colamd_stats [COLAMD_DENSE_COL] ;
+       Info [UMFPACK_SYMBOLIC_DEFRAG] = colamd_stats [COLAMD_DEFRAG_COUNT] ;
+
+       /* re-analyze if any "dense" rows or cols ignored by UMF_colamd */
+       do_UMF_analyze =
+           colamd_stats [COLAMD_DENSE_ROW] > 0 ||
+           colamd_stats [COLAMD_DENSE_COL] > 0 ;
+
+       /* Combine the singleton and colamd ordering into Cperm_init */
+       /* Note that colamd returns its inverse permutation in Ci */
+       combine_ordering (n1, nempty_col, n_col, Cperm_init, Cperm1, Ci) ;
+
+       /* contents of Ci no longer needed */
+
+#ifndef NDEBUG
+       for (col = 0 ; col < n_col ; col++)
+       {
+           DEBUG1 (("Cperm_init ["ID"] = "ID"\n", col, Cperm_init[col]));
+       }
+       /* make sure colamd returned a valid permutation */
+       ASSERT (Cperm_init != (Int *) NULL) ;
+       ASSERT (UMF_is_permutation (Cperm_init, Ci, n_col, n_col)) ;
+#endif
+
+    }
+    else
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* do not call colamd - use input Quser or AMD instead */
+       /* ------------------------------------------------------------------ */
+
+       /* The ordering (Quser or Qamd) is already in Cperm_init */
+       do_UMF_analyze = TRUE ;
+
+    }
+
+    Cperm_init [n_col] = EMPTY ;       /* unused in Cperm_init */
+
+    /* ---------------------------------------------------------------------- */
+    /* AMD ordering, if it exists, has been copied into Cperm_init */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    DEBUG3 (("Cperm_init column permutation:\n")) ;
+    ASSERT (UMF_is_permutation (Cperm_init, Ci, n_col, n_col)) ;
+    for (k = 0 ; k < n_col ; k++)
+    {
+       DEBUG3 ((ID"\n", Cperm_init [k])) ;
+    }
+    /* ensure that empty columns have been placed last in A (:,Cperm_init) */
+    for (newj = 0 ; newj < n_col ; newj++)
+    {
+       /* empty columns will be last in A (:, Cperm_init (1:n_col)) */
+       j = Cperm_init [newj] ;
+       ASSERT (IMPLIES (newj >= n_col-nempty_col, Cdeg [j] == 0)) ;
+       ASSERT (IMPLIES (newj <  n_col-nempty_col, Cdeg [j] > 0)) ;
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* symbolic factorization (unless colamd has already done it) */
+    /* ---------------------------------------------------------------------- */
+
+    if (do_UMF_analyze)
+    {
+
+       Int *W, *Bp, *Bi, *Cperm2, ok, *P, Clen2, bsize, Clen0 ;
+
+       /* ------------------------------------------------------------------ */
+       /* construct column pre-ordered, pruned submatrix */
+       /* ------------------------------------------------------------------ */
+
+       /* S = column form submatrix after removing singletons and applying
+        * initial column ordering (includes singleton ordering) */
+       (void) prune_singletons (n1, n_col, Ap, Ai,
+           (double *) NULL,
+#ifdef COMPLEX
+           (double *) NULL,
+#endif
+           Cperm_init, InvRperm1, Si, Sp
+#ifndef NDEBUG
+           , Rperm1, n_row
+#endif
+           ) ;
+
+       /* ------------------------------------------------------------------ */
+       /* Ci [0 .. Clen-1] holds the following work arrays:
+
+               first Clen0 entries     empty space, where Clen0 =
+                                       Clen - (nn+1 + 2*nn + n_col)
+                                       and Clen0 >= nz + n_col
+               next nn+1 entries       Bp [0..nn]
+               next nn entries         Link [0..nn-1]
+               next nn entries         W [0..nn-1]
+               last n_col entries      Cperm2 [0..n_col-1]
+
+           We have Clen >= n_col + MAX (nz,n_col) + 3*nn+1 + n_col,
+           So  Clen0 >= 2*n_col as required for AMD_postorder
+           and Clen0 >= n_col + nz as required
+       */
+
+       Clen0 = Clen - (nn+1 + 2*nn + n_col) ;
+       Bp = Ci + Clen0 ;
+       Link = Bp + (nn+1) ;
+       W = Link + nn ;
+       Cperm2 = W + nn ;
+       ASSERT (Cperm2 + n_col == Ci + Clen) ;
+       ASSERT (Clen0 >= nz + n_col) ;
+       ASSERT (Clen0 >= 2*n_col) ;
+
+       /* ------------------------------------------------------------------ */
+       /* P = order that rows will be used in UMF_analyze */
+       /* ------------------------------------------------------------------ */
+
+       /* use W to mark rows, and use Link for row permutation P [ [ */
+       for (row = 0 ; row < n_row - n1 ; row++)
+       {
+           W [row] = FALSE ;
+       }
+       P = Link ;
+
+       k = 0 ;
+
+       for (col = 0 ; col < n_col - n1 ; col++)
+       {
+           /* empty columns are last in S */
+           for (p = Sp [col] ; p < Sp [col+1] ; p++)
+           {
+               row = Si [p] ;
+               if (!W [row])
+               {
+                   /* this row has just been seen for the first time */
+                   W [row] = TRUE ;
+                   P [k++] = row ;
+               }
+           }
+       }
+
+       /* If the matrix has truly empty rows, then P will not be */
+       /* complete, and visa versa.  The matrix is structurally singular. */
+       nempty_row = n_row - n1 - k ;
+       if (k < n_row - n1)
+       {
+           /* complete P by putting empty rows last in their natural order, */
+           /* rather than declaring an error (the matrix is singular) */
+           for (row = 0 ; row < n_row - n1 ; row++)
+           {
+               if (!W [row])
+               {
+                   /* W [row] = TRUE ;  (not required) */
+                   P [k++] = row ;
+               }
+           }
+       }
+
+       /* contents of W no longer needed ] */
+
+#ifndef NDEBUG
+       DEBUG3 (("Induced row permutation:\n")) ;
+       ASSERT (k == n_row - n1) ;
+       ASSERT (UMF_is_permutation (P, W, n_row - n1, n_row - n1)) ;
+       for (k = 0 ; k < n_row - n1 ; k++)
+       {
+           DEBUG3 ((ID"\n", P [k])) ;
+       }
+#endif
+
+       /* ------------------------------------------------------------------ */
+       /* B = row-form of the pattern of S (excluding empty columns) */
+       /* ------------------------------------------------------------------ */
+
+       /* Ci [0 .. Clen-1] holds the following work arrays:
+
+               first Clen2 entries     empty space, must be at least >= n_col
+               next max (nz,1)         Bi [0..max (nz,1)-1]
+               next nn+1 entries       Bp [0..nn]
+               next nn entries         Link [0..nn-1]
+               next nn entries         W [0..nn-1]
+               last n_col entries      Cperm2 [0..n_col-1]
+
+               This memory usage is accounted for by the UMF_ANALYZE_CLEN
+               macro.
+       */
+
+       Clen2 = Clen0 ;
+       snz = Sp [n_col - n1] ;
+       bsize = MAX (snz, 1) ;
+       Clen2 -= bsize ;
+       Bi = Ci + Clen2 ;
+       ASSERT (Clen2 >= n_col) ;
+
+       (void) UMF_transpose (n_row - n1, n_col - n1 - nempty_col,
+           Sp, Si, (double *) NULL,
+           P, (Int *) NULL, 0, Bp, Bi, (double *) NULL, W, FALSE
+#ifdef COMPLEX
+           , (double *) NULL, (double *) NULL, FALSE
+#endif
+           ) ;
+
+       /* contents of Si and Sp no longer needed */
+
+       /* contents of P (same as Link) and W not needed */
+       /* still need Link and W as work arrays, though ] */
+
+       ASSERT (Bp [0] == 0) ;
+       ASSERT (Bp [n_row - n1] == snz) ;
+
+       /* increment Bp to point into Ci, not Bi */
+       for (i = 0 ; i <= n_row - n1 ; i++)
+       {
+           Bp [i] += Clen2 ;
+       }
+       ASSERT (Bp [0] == Clen0 - bsize) ;
+       ASSERT (Bp [n_row - n1] <= Clen0) ;
+
+       /* Ci [0 .. Clen-1] holds the following work arrays:
+
+               first Clen0 entries     Ci [0 .. Clen0-1], where the col indices
+                                       of B are at the tail end of this part,
+                                       and Bp [0] = Clen2 >= n_col.  Note
+                                       that Clen0 = Clen2 + max (snz,1).
+               next nn+1 entries       Bp [0..nn]
+               next nn entries         Link [0..nn-1]
+               next nn entries         W [0..nn-1]
+               last n_col entries      Cperm2 [0..n_col-1]
+       */
+
+       /* ------------------------------------------------------------------ */
+       /* analyze */
+       /* ------------------------------------------------------------------ */
+
+       /* only analyze the non-empty, non-singleton part of the matrix */
+       ok = UMF_analyze (
+               n_row - n1 - nempty_row,
+               n_col - n1 - nempty_col,
+               Ci, Bp, Cperm2, fixQ, W, Link,
+               Fr_ncols, Fr_nrows, Fr_npivcol,
+               Fr_parent, &nfr, &analyze_compactions) ;
+       if (!ok)
+       {
+           /* :: internal error in umf_analyze :: */
+           Info [UMFPACK_STATUS] = UMFPACK_ERROR_internal_error ;
+           error (&Symbolic, SW) ;
+           return (UMFPACK_ERROR_internal_error) ;
+       }
+       Info [UMFPACK_SYMBOLIC_DEFRAG] += analyze_compactions ;
+
+       /* ------------------------------------------------------------------ */
+       /* combine the input permutation and UMF_analyze's permutation */
+       /* ------------------------------------------------------------------ */
+
+       if (!fixQ)
+       {
+           /* Cperm2 is the column etree post-ordering */
+           ASSERT (UMF_is_permutation (Cperm2, W,
+           n_col-n1-nempty_col, n_col-n1-nempty_col)) ;
+
+           /* Note that the empty columns remain at the end of Cperm_init */
+           for (k = 0 ; k < n_col - n1 - nempty_col ; k++)
+           {
+               W [k] = Cperm_init [n1 + Cperm2 [k]] ;
+           }
+
+           for (k = 0 ; k < n_col - n1 - nempty_col ; k++)
+           {
+               Cperm_init [n1 + k] = W [k] ;
+           }
+       }
+
+       ASSERT (UMF_is_permutation (Cperm_init, W, n_col, n_col)) ;
+
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* free some of the workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* (4) The real workspace, Rs, of size n_row doubles has already been
+     * free'd.  An additional workspace of size nz + n_col+1 + n_col integers
+     * is now free'd as well. */
+
+    SW->Si = (Int *) UMF_free ((void *) SW->Si) ;
+    SW->Sp = (Int *) UMF_free ((void *) SW->Sp) ;
+    SW->Cperm1 = (Int *) UMF_free ((void *) SW->Cperm1) ;
+    ASSERT (SW->Rs == (double *) NULL) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* determine the size of the Symbolic object */
+    /* ---------------------------------------------------------------------- */
+
+    /* ---------------------------------------------------------------------- */
+    /* determine the size of the Symbolic object */
+    /* ---------------------------------------------------------------------- */
+
+    nchains = 0 ;
+    for (i = 0 ; i < nfr ; i++)
+    {
+       if (Fr_parent [i] != i+1)
+       {
+           nchains++ ;
+       }
+    }
+
+    Symbolic->nchains = nchains ;
+    Symbolic->nfr = nfr ;
+    Symbolic->esize
+       = (max_rdeg > dense_row_threshold) ? (n_col - n1 - nempty_col) : 0 ;
+
+    /* true size of Symbolic object */
+    Info [UMFPACK_SYMBOLIC_SIZE] = UMF_symbolic_usage (n_row, n_col, nchains,
+           nfr, Symbolic->esize, prefer_diagonal) ;
+
+    /* actual peak memory usage for UMFPACK_symbolic (actual nfr, nchains) */
+    Info [UMFPACK_SYMBOLIC_PEAK_MEMORY] =
+       SYM_WORK_USAGE (n_col, n_row, Clen) + Info [UMFPACK_SYMBOLIC_SIZE] ;
+    Symbolic->peak_sym_usage = Info [UMFPACK_SYMBOLIC_PEAK_MEMORY] ;
+
+    DEBUG0 (("Number of fronts: "ID"\n", nfr)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the second part of the Symbolic object (Front_*, Chain_*) */
+    /* ---------------------------------------------------------------------- */
+
+    /* (5) UMF_malloc is called 7 or 8 times, for a total space of
+     * (4*(nfr+1) + 3*(nchains+1) + esize) integers, where nfr is the total
+     * number of frontal matrices and nchains is the total number of frontal
+     * matrix chains, and where nchains <= nfr <= n_col.  esize is zero if there
+     * are no dense rows, or n_col-n1-nempty_col otherwise (n1 is the number of
+     * singletons and nempty_col is the number of empty columns).  This space is
+     * part of the Symbolic object and is not free'd unless an error occurs.
+     * This is between 7 and about 8n integers when A is square.
+     */
+
+    /* Note that Symbolic->Front_* does include the dummy placeholder front */
+    Symbolic->Front_npivcol = (Int *) UMF_malloc (nfr+1, sizeof (Int)) ;
+    Symbolic->Front_parent = (Int *) UMF_malloc (nfr+1, sizeof (Int)) ;
+    Symbolic->Front_1strow = (Int *) UMF_malloc (nfr+1, sizeof (Int)) ;
+    Symbolic->Front_leftmostdesc = (Int *) UMF_malloc (nfr+1, sizeof (Int)) ;
+    Symbolic->Chain_start = (Int *) UMF_malloc (nchains+1, sizeof (Int)) ;
+    Symbolic->Chain_maxrows = (Int *) UMF_malloc (nchains+1, sizeof (Int)) ;
+    Symbolic->Chain_maxcols = (Int *) UMF_malloc (nchains+1, sizeof (Int)) ;
+
+    fail = (!Symbolic->Front_npivcol || !Symbolic->Front_parent ||
+       !Symbolic->Front_1strow || !Symbolic->Front_leftmostdesc ||
+       !Symbolic->Chain_start || !Symbolic->Chain_maxrows ||
+       !Symbolic->Chain_maxcols) ;
+
+    if (Symbolic->esize > 0)
+    {
+       Symbolic->Esize = (Int *) UMF_malloc (Symbolic->esize, sizeof (Int)) ;
+       fail = fail || !Symbolic->Esize ;
+    }
+
+    if (fail)
+    {
+       DEBUGm4 (("out of memory: rest of symbolic object\n")) ;
+       Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+       error (&Symbolic, SW) ;
+       return (UMFPACK_ERROR_out_of_memory) ;
+    }
+    DEBUG0 (("Symbolic UMF_malloc_count - init_count = "ID"\n",
+       UMF_malloc_count - init_count)) ;
+    ASSERT (UMF_malloc_count == init_count + 21
+       + (SW->Rperm_2by2 != (Int *) NULL)
+       + (Symbolic->Esize != (Int *) NULL)) ;
+
+    Front_npivcol = Symbolic->Front_npivcol ;
+    Front_parent = Symbolic->Front_parent ;
+    Front_1strow = Symbolic->Front_1strow ;
+    Front_leftmostdesc = Symbolic->Front_leftmostdesc ;
+
+    Chain_start = Symbolic->Chain_start ;
+    Chain_maxrows = Symbolic->Chain_maxrows ;
+    Chain_maxcols = Symbolic->Chain_maxcols ;
+
+    Esize = Symbolic->Esize ;
+
+    /* ---------------------------------------------------------------------- */
+    /* assign rows to fronts */
+    /* ---------------------------------------------------------------------- */
+
+    /* find InFront, unless colamd has already computed it */
+    if (do_UMF_analyze)
+    {
+
+       DEBUGm4 ((">>>>>>>>>Computing Front_1strow from scratch\n")) ;
+       /* empty rows go to dummy front nfr */
+       for (row = 0 ; row < n_row ; row++)
+       {
+           InFront [row] = nfr ;       
+       }
+       /* assign the singleton pivot rows to the "empty" front */
+       for (k = 0 ; k < n1 ; k++)
+       {
+           row = Rperm1 [k] ;
+           InFront [row] = EMPTY ;
+       }
+       DEBUG1 (("Front (EMPTY), singleton nrows "ID" ncols "ID"\n", k, k)) ;
+       newj = n1 ;
+       for (i = 0 ; i < nfr ; i++)
+       {
+           fpivcol = Fr_npivcol [i] ;
+           f1rows = 0 ;
+           /* for all pivot columns in front i */
+           for (kk = 0 ; kk < fpivcol ; kk++, newj++)
+           {
+               j = Cperm_init [newj] ;
+               ASSERT (IMPLIES (newj >= n_col-nempty_col,
+                               Ap [j+1] - Ap [j] == 0));
+               for (p = Ap [j] ; p < Ap [j+1] ; p++)
+               {
+                   row = Ai [p] ;
+                   if (InFront [row] == nfr)
+                   {
+                       /* this row belongs to front i */
+                       DEBUG1 (("    Row "ID" in Front "ID"\n", row, i)) ;
+                       InFront [row] = i ;
+                       f1rows++ ;
+                   }
+               }
+           }
+           Front_1strow [i] = f1rows ;
+           DEBUG1 (("    Front "ID" has 1strows: "ID" pivcols "ID"\n",
+               i, f1rows, fpivcol)) ;
+       }
+
+    }
+    else
+    {
+
+       /* COLAMD has already computed InFront, but it is not yet
+        * InFront [row] = front i, where row is an original row.  It is
+        * InFront [k-n1] = i for k in the range n1 to n_row-nempty_row,
+        * and where row = Rperm1 [k].  Need to permute InFront.  Also compute
+        * # of original rows assembled into each front.
+        * [ use Ci as workspace */
+       DEBUGm4 ((">>>>>>>>>Computing Front_1strow from colamd's InFront\n")) ;
+       for (i = 0 ; i <= nfr ; i++)
+       {
+           Front_1strow [i] = 0 ;
+       }
+       /* assign the singleton pivot rows to "empty" front */
+       for (k = 0 ; k < n1 ; k++)
+       {
+           row = Rperm1 [k] ;
+           Ci [row] = EMPTY ;
+       }
+       /* assign the non-empty rows to the front that assembled them */
+       for ( ; k < n_row - nempty_row ; k++)
+       {
+           row = Rperm1 [k] ;
+           i = InFront [k - n1] ;
+           ASSERT (i >= EMPTY && i < nfr) ;
+           if (i != EMPTY)
+           {
+               Front_1strow [i]++ ;
+           }
+           /* use Ci as permuted version of InFront */
+           Ci [row] = i ;
+       }
+       /* empty rows go to the "dummy" front */
+       for ( ; k < n_row ; k++)
+       {
+           row = Rperm1 [k] ;
+           Ci [row] = nfr ;
+       }
+       /* permute InFront so that InFront [row] = i if the original row is
+        * in front i */
+       for (row = 0 ; row < n_row ; row++)
+       {
+           InFront [row] = Ci [row] ;
+       }
+       /* ] no longer need Ci as workspace */
+    }
+
+#ifndef NDEBUG
+    for (row = 0 ; row < n_row ; row++)
+    {
+       if (InFront [row] == nfr)
+       {
+           DEBUG1 (("    Row "ID" in Dummy Front "ID"\n", row, nfr)) ;
+       }
+       else if (InFront [row] == EMPTY)
+       {
+           DEBUG1 (("    singleton Row "ID"\n", row)) ;
+       }
+       else
+       {
+           DEBUG1 (("    Row "ID" in Front "ID"\n", row, nfr)) ;
+       }
+    }
+    for (i = 0 ; i <= nfr ; i++)
+    {
+       DEBUG1 (("Front "ID" has 1strows: "ID" pivcols "ID"\n",
+               i, f1rows, fpivcol)) ;
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* copy front information into Symbolic object */
+    /* ---------------------------------------------------------------------- */
+
+    k = n1 ;
+    for (i = 0 ; i < nfr ; i++)
+    {
+       fpivcol = Fr_npivcol [i] ;
+       DEBUG1 (("Front "ID" k "ID" npivcol "ID" nrows "ID" ncols "ID"\n",
+           i, k, fpivcol, Fr_nrows [i], Fr_ncols [i])) ;
+       k += fpivcol ;
+       /* copy Front info into Symbolic object from SW */
+       Front_npivcol [i] = fpivcol ;
+       Front_parent [i] = Fr_parent [i] ;
+    }
+
+    /* assign empty columns to dummy placehold front nfr */
+    DEBUG1 (("Dummy Cols in Front "ID" : "ID"\n", nfr, n_col-k)) ;
+    Front_npivcol [nfr] = n_col - k ;
+    Front_parent [nfr] = EMPTY ;
+
+    /* ---------------------------------------------------------------------- */
+    /* find initial row permutation */
+    /* ---------------------------------------------------------------------- */
+
+    /* order the singleton pivot rows */
+    for (k = 0 ; k < n1 ; k++)
+    {
+       Rperm_init [k] = Rperm1 [k] ;
+    }
+
+    /* determine the first row in each front (in the new row ordering) */
+    for (i = 0 ; i < nfr ; i++)
+    {
+       f1rows = Front_1strow [i] ;
+       DEBUG1 (("Front "ID" : npivcol "ID" parent "ID,
+           i, Front_npivcol [i], Front_parent [i])) ;
+       DEBUG1 (("    1st rows in Front "ID" : "ID"\n", i, f1rows)) ;
+       Front_1strow [i] = k ;
+       k += f1rows ;
+    }
+
+    /* assign empty rows to dummy placehold front nfr */
+    DEBUG1 (("Rows in Front "ID" (dummy): "ID"\n", nfr, n_row-k)) ;
+    Front_1strow [nfr] = k ;
+    DEBUG1 (("nfr "ID" 1strow[nfr] "ID" nrow "ID"\n", nfr, k, n_row)) ;
+
+    /* Use Ci as temporary workspace for F1 */
+    F1 = Ci ;                          /* [ of size nfr+1 */
+    ASSERT (Clen >= 2*n_row + nfr+1) ;
+
+    for (i = 0 ; i <= nfr ; i++)
+    {
+       F1 [i] = Front_1strow [i] ;
+    }
+
+    for (row = 0 ; row < n_row ; row++)
+    {
+       i = InFront [row] ;
+       if (i != EMPTY)
+       {
+           newrow = F1 [i]++ ;
+           ASSERT (newrow >= n1) ;
+           Rperm_init [newrow] = row ;
+       }
+    }
+    Rperm_init [n_row] = EMPTY ;       /* unused */
+
+#ifndef NDEBUG
+    for (k = 0 ; k < n_row ; k++)
+    {
+       DEBUG2 (("Rperm_init ["ID"] = "ID"\n", k, Rperm_init [k])) ;
+    }
+#endif
+
+    /* ] done using F1 */
+
+    /* ---------------------------------------------------------------------- */
+    /* find the diagonal map */
+    /* ---------------------------------------------------------------------- */
+
+    /* Rperm_init [newrow] = row gives the row permutation that is implied
+     * by the column permutation, where "row" is a row index of the original
+     * matrix A.  It is not dependent on the Rperm_2by2 permutation, which
+     * only redefines the "diagonal".   Both are used to construct the
+     * Diagonal_map.  Diagonal_map only needs to be defined for
+     * k = n1 to nn - nempty, but go ahead and define it for all of
+     * k = 0 to nn */
+
+    if (prefer_diagonal)
+    {
+       Int *Diagonal_map ;
+       ASSERT (n_row == n_col && nn == n_row) ;
+       ASSERT (nempty_row == nempty_col && nempty == nempty_row) ;
+
+       /* allocate the Diagonal_map */
+       Symbolic->Diagonal_map = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ;
+       Diagonal_map = Symbolic->Diagonal_map ;
+       if (Diagonal_map == (Int *) NULL)
+       {
+           /* :: out of memory (diagonal map) :: */
+           DEBUGm4 (("out of memory: Diagonal map\n")) ;
+           Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+           error (&Symbolic, SW) ;
+           return (UMFPACK_ERROR_out_of_memory) ;
+       }
+
+       /* use Ci as workspace to compute the inverse of Rperm_init [ */
+       for (newrow = 0 ; newrow < nn ; newrow++)
+       {
+           oldrow = Rperm_init [newrow] ;
+           ASSERT (oldrow >= 0 && oldrow < nn) ;
+           Ci [oldrow] = newrow ;
+       }
+       if (strategy == UMFPACK_STRATEGY_2BY2)
+       {
+           ASSERT (Rperm_2by2 != (Int *) NULL) ;
+           for (newcol = 0 ; newcol < nn ; newcol++)
+           {
+               oldcol = Cperm_init [newcol] ;
+               /* 2-by-2 pivoting done in S */
+               oldrow = Rperm_2by2 [oldcol] ;
+               newrow = Ci [oldrow] ;
+               Diagonal_map [newcol] = newrow ;
+           }
+       }
+       else
+       {
+           for (newcol = 0 ; newcol < nn ; newcol++)
+           {
+               oldcol = Cperm_init [newcol] ;
+               /* no 2-by-2 pivoting in S */
+               oldrow = oldcol ;
+               newrow = Ci [oldrow] ;
+               Diagonal_map [newcol] = newrow ;
+           }
+       }
+
+#ifndef NDEBUG
+       DEBUG1 (("\nDiagonal map:\n")) ;
+       for (newcol = 0 ; newcol < nn ; newcol++)
+       {
+           oldcol = Cperm_init [newcol] ;
+           DEBUG3 (("oldcol "ID" newcol "ID":\n", oldcol, newcol)) ;
+           for (p = Ap [oldcol] ; p < Ap [oldcol+1] ; p++)
+           {
+               Entry aij ;
+               oldrow = Ai [p] ;
+               newrow = Ci [oldrow] ;
+               if (Ax != (double *) NULL
+#ifdef COMPLEX
+                && Az != (double *) NULL
+#endif
+                       )
+               {
+                   ASSIGN (aij, Ax [p], Az [p]) ;
+               }
+               if (oldrow == oldcol)
+               {
+                   DEBUG2 (("     old diagonal : oldcol "ID" oldrow "ID" ",
+                           oldcol, oldrow)) ;
+                   EDEBUG2 (aij) ;
+                   DEBUG2 (("\n")) ;
+               }
+               if (newrow == Diagonal_map [newcol])
+               {
+                   DEBUG2 (("     MAP diagonal : newcol "ID" MAProw "ID" ",
+                           newcol, Diagonal_map [newrow])) ;
+                   EDEBUG2 (aij) ;
+                   DEBUG2 (("\n")) ;
+               }
+           }
+       }
+#endif
+       /* done using Ci as workspace ] */
+
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* find the leftmost descendant of each front */
+    /* ---------------------------------------------------------------------- */
+
+    for (i = 0 ; i <= nfr ; i++)
+    {
+       Front_leftmostdesc [i] = EMPTY ;
+    }
+
+    for (i = 0 ; i < nfr ; i++)
+    {
+       /* start at i and walk up the tree */
+       DEBUG2 (("Walk up front tree from "ID"\n", i)) ;
+       j = i ;
+       while (j != EMPTY && Front_leftmostdesc [j] == EMPTY)
+       {
+           DEBUG3 (("  Leftmost desc of "ID" is "ID"\n", j, i)) ;
+           Front_leftmostdesc [j] = i ;
+           j = Front_parent [j] ;
+           DEBUG3 (("  go to j = "ID"\n", j)) ;
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* find the frontal matrix chains and max frontal matrix sizes */
+    /* ---------------------------------------------------------------------- */
+
+    maxnrows = 1 ;             /* max # rows in any front */
+    maxncols = 1 ;             /* max # cols in any front */
+    dmaxfrsize = 1 ;           /* max frontal matrix size */
+
+    /* start the first chain */
+    nchains = 0 ;              /* number of chains */
+    Chain_start [0] = 0 ;      /* front 0 starts a new chain */
+    maxrows = 1 ;              /* max # rows for any front in current chain */
+    maxcols = 1 ;              /* max # cols for any front in current chain */
+    DEBUG1 (("Constructing chains:\n")) ;
+
+    for (i = 0 ; i < nfr ; i++)
+    {
+       /* get frontal matrix info */
+       fpivcol  = Front_npivcol [i] ;      /* # candidate pivot columns */
+       fallrows = Fr_nrows [i] ;           /* all rows (not just Schur comp) */
+       fallcols = Fr_ncols [i] ;           /* all cols (not just Schur comp) */
+       parent = Front_parent [i] ;         /* parent in column etree */
+       fpiv = MIN (fpivcol, fallrows) ;    /* # pivot rows and cols */
+       maxrows = MAX (maxrows, fallrows) ;
+       maxcols = MAX (maxcols, fallcols) ;
+
+       DEBUG1 (("Front: "ID", pivcol "ID", "ID"-by-"ID" parent "ID
+           ", npiv "ID" Chain: maxrows "ID" maxcols "ID"\n", i, fpivcol,
+           fallrows, fallcols, parent, fpiv, maxrows, maxcols)) ;
+
+       if (parent != i+1)
+       {
+           /* this is the end of a chain */
+           double s ;
+           DEBUG1 (("\nEnd of chain "ID"\n", nchains)) ;
+
+           /* make sure maxrows is an odd number */
+           ASSERT (maxrows >= 0) ;
+           if (maxrows % 2 == 0) maxrows++ ;
+
+           DEBUG1 (("Chain maxrows "ID" maxcols "ID"\n", maxrows, maxcols)) ;
+
+           Chain_maxrows [nchains] = maxrows ;
+           Chain_maxcols [nchains] = maxcols ;
+
+           /* keep track of the maximum front size for all chains */
+
+           /* for Info only: */
+           s = (double) maxrows * (double) maxcols ;
+           dmaxfrsize = MAX (dmaxfrsize, s) ;
+
+           /* for the subsequent numerical factorization */
+           maxnrows = MAX (maxnrows, maxrows) ;
+           maxncols = MAX (maxncols, maxcols) ;
+
+           DEBUG1 (("Chain dmaxfrsize %g\n\n", dmaxfrsize)) ;
+
+           /* start the next chain */
+           nchains++ ;
+           Chain_start [nchains] = i+1 ;
+           maxrows = 1 ;
+           maxcols = 1 ;
+       }
+    }
+
+    /* for Info only: */
+    dmaxfrsize = ceil (dmaxfrsize) ;
+    DEBUGm1 (("dmaxfrsize %30.20g Int_MAX "ID"\n", dmaxfrsize, Int_MAX)) ;
+    ASSERT (Symbolic->nchains == nchains) ;
+
+    /* For allocating objects in umfpack_numeric (does not include all possible
+     * pivots, particularly pivots from prior fronts in the chain.  Need to add
+     * nb to these to get the # of columns in the L block, for example.  This
+     * is the largest row dimension and largest column dimension of any frontal
+     * matrix.  maxnrows is always odd. */
+    Symbolic->maxnrows = maxnrows ;
+    Symbolic->maxncols = maxncols ;
+    DEBUGm3 (("maxnrows "ID" maxncols "ID"\n", maxnrows, maxncols)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* find the initial element sizes */
+    /* ---------------------------------------------------------------------- */
+
+    if (max_rdeg > dense_row_threshold)
+    {
+       /* there are one or more dense rows in the input matrix */
+       /* count the number of dense rows in each column */
+       /* use Ci as workspace for inverse of Rperm_init [ */
+       ASSERT (Esize != (Int *) NULL) ;
+       for (newrow = 0 ; newrow < n_row ; newrow++)
+       {
+           oldrow = Rperm_init [newrow] ;
+           ASSERT (oldrow >= 0 && oldrow < nn) ;
+           Ci [oldrow] = newrow ;
+       }
+       for (col = n1 ; col < n_col - nempty_col ; col++)
+       {
+           oldcol = Cperm_init [col] ;
+           esize = Cdeg [oldcol] ;
+           ASSERT (esize > 0) ;
+           for (p = Ap [oldcol] ; p < Ap [oldcol+1] ; p++)
+           {
+               oldrow = Ai [p] ;
+               newrow = Ci [oldrow] ;
+               if (newrow >= n1 && Rdeg [oldrow] > dense_row_threshold)
+               {
+                   esize-- ;
+               }
+           }
+           ASSERT (esize >= 0) ;
+           Esize [col - n1] = esize ;
+       }
+       /* done using Ci as workspace ] */
+    }
+
+    /* If there are no dense rows, then Esize [col-n1] is identical to
+     * Cdeg [col], once Cdeg is permuted below */
+
+    /* ---------------------------------------------------------------------- */
+    /* permute Cdeg and Rdeg according to initial column and row permutation */
+    /* ---------------------------------------------------------------------- */
+
+    /* use Ci as workspace [ */
+    for (k = 0 ; k < n_col ; k++)
+    {
+       Ci [k] = Cdeg [Cperm_init [k]] ;
+    }
+    for (k = 0 ; k < n_col ; k++)
+    {
+       Cdeg [k] = Ci [k] ;
+    }
+    for (k = 0 ; k < n_row ; k++)
+    {
+       Ci [k] = Rdeg [Rperm_init [k]] ;
+    }
+    for (k = 0 ; k < n_row ; k++)
+    {
+       Rdeg [k] = Ci [k] ;
+    }
+    /* done using Ci as workspace ] */
+
+    /* ---------------------------------------------------------------------- */
+    /* simulate UMF_kernel_init */
+    /* ---------------------------------------------------------------------- */
+
+    /* count elements and tuples at tail, LU factors of singletons, and
+     * head and tail markers */
+
+    dlnz = n_inner ;   /* upper limit of nz in L (incl diag) */
+    dunz = dlnz ;      /* upper limit of nz in U (incl diag) */
+
+    /* head marker */
+    head_usage  = 1 ;
+    dhead_usage = 1 ;
+
+    /* tail markers: */
+    tail_usage  = 2 ;
+    dtail_usage = 2 ;
+
+    /* allocate the Rpi and Rpx workspace for UMF_kernel_init (incl. headers) */
+    tail_usage  +=  UNITS (Int *, n_row+1) +  UNITS (Entry *, n_row+1) + 2 ;
+    dtail_usage += DUNITS (Int *, n_row+1) + DUNITS (Entry *, n_row+1) + 2 ;
+    DEBUG1 (("Symbolic usage after Rpi/Rpx allocation: head "ID" tail "ID"\n",
+       head_usage, tail_usage)) ;
+
+    /* LU factors for singletons, at the head of memory */
+    for (k = 0 ; k < n1 ; k++)
+    {
+       lnz = Cdeg [k] - 1 ;
+       unz = Rdeg [k] - 1 ;
+       dlnz += lnz ;
+       dunz += unz ;
+       DEBUG1 (("singleton k "ID" pivrow "ID" pivcol "ID" lnz "ID" unz "ID"\n",
+           k, Rperm_init [k], Cperm_init [k], lnz, unz)) ;
+       head_usage  +=  UNITS (Int, lnz) +  UNITS (Entry, lnz)
+                   +   UNITS (Int, unz) +  UNITS (Entry, unz) ;
+       dhead_usage += DUNITS (Int, lnz) + DUNITS (Entry, lnz)
+                   +  DUNITS (Int, unz) + DUNITS (Entry, unz) ;
+    }
+    DEBUG1 (("Symbolic init head usage: "ID" for LU singletons\n",head_usage)) ;
+
+    /* column elements: */
+    for (k = n1 ; k < n_col - nempty_col; k++)
+    {
+       esize = Esize ? Esize [k-n1] : Cdeg [k] ;
+       DEBUG2 (("   esize: "ID"\n", esize)) ;
+       ASSERT (esize >= 0) ;
+       if (esize > 0)
+       {
+           tail_usage  +=  GET_ELEMENT_SIZE (esize, 1) + 1 ;
+           dtail_usage += DGET_ELEMENT_SIZE (esize, 1) + 1 ;
+       }
+    }
+
+    /* dense row elements */
+    if (Esize)
+    {
+       Int nrow_elements = 0 ;
+       for (k = n1 ; k < n_row - nempty_row ; k++)
+       {
+           rdeg = Rdeg [k] ;
+           if (rdeg > dense_row_threshold)
+           {
+               tail_usage  += GET_ELEMENT_SIZE (1, rdeg) + 1 ;
+               dtail_usage += GET_ELEMENT_SIZE (1, rdeg) + 1 ;
+               nrow_elements++ ;
+           }
+       }
+       Info [UMFPACK_NDENSE_ROW] = nrow_elements ;
+    }
+
+    DEBUG1 (("Symbolic usage: "ID" = head "ID" + tail "ID" after els\n",
+       head_usage + tail_usage, head_usage, tail_usage)) ;
+
+    /* compute the tuple lengths */
+    if (Esize)
+    {
+       /* row tuples */
+       for (row = n1 ; row < n_row ; row++)
+       {
+           rdeg = Rdeg [row] ;
+           tlen = (rdeg > dense_row_threshold) ? 1 : rdeg ;
+           tail_usage  += 1 +  UNITS (Tuple, TUPLES (tlen)) ;
+           dtail_usage += 1 + DUNITS (Tuple, TUPLES (tlen)) ;
+       }
+       /* column tuples */
+       for (col = n1 ; col < n_col - nempty_col ; col++)
+       {
+           /* tlen is 1 plus the number of dense rows in this column */
+           esize = Esize [col - n1] ;
+           tlen = (esize > 0) + (Cdeg [col] - esize) ;
+           tail_usage  += 1 +  UNITS (Tuple, TUPLES (tlen)) ;
+           dtail_usage += 1 + DUNITS (Tuple, TUPLES (tlen)) ;
+       }
+       for ( ; col < n_col ; col++)
+       {
+           tail_usage  += 1 +  UNITS (Tuple, TUPLES (0)) ;
+           dtail_usage += 1 + DUNITS (Tuple, TUPLES (0)) ;
+       }
+    }
+    else
+    {
+       /* row tuples */
+       for (row = n1 ; row < n_row ; row++)
+       {
+           tlen = Rdeg [row] ;
+           tail_usage  += 1 +  UNITS (Tuple, TUPLES (tlen)) ;
+           dtail_usage += 1 + DUNITS (Tuple, TUPLES (tlen)) ;
+       }
+       /* column tuples */
+       for (col = n1 ; col < n_col ; col++)
+       {
+           tail_usage  += 1 +  UNITS (Tuple, TUPLES (1)) ;
+           dtail_usage += 1 + DUNITS (Tuple, TUPLES (1)) ;
+       }
+    }
+
+    Symbolic->num_mem_init_usage = head_usage + tail_usage ;
+    DEBUG1 (("Symbolic usage: "ID" = head "ID" + tail "ID" final\n",
+       Symbolic->num_mem_init_usage, head_usage, tail_usage)) ;
+
+    ASSERT (UMF_is_permutation (Rperm_init, Ci, n_row, n_row)) ;
+
+    /* initial head and tail usage in Numeric->Memory */
+    dmax_usage = dhead_usage + dtail_usage ;
+    dmax_usage = MAX (Symbolic->num_mem_init_usage, ceil (dmax_usage)) ;
+    Info [UMFPACK_VARIABLE_INIT_ESTIMATE] = dmax_usage ;
+
+    /* In case Symbolic->num_mem_init_usage overflows, keep as a double, too */
+    Symbolic->dnum_mem_init_usage = dmax_usage ;
+
+    /* free the Rpi and Rpx workspace */
+    tail_usage  -=  UNITS (Int *, n_row+1) +  UNITS (Entry *, n_row+1) ;
+    dtail_usage -= DUNITS (Int *, n_row+1) + DUNITS (Entry *, n_row+1) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* simulate UMF_kernel, assuming unsymmetric pivoting */
+    /* ---------------------------------------------------------------------- */
+
+    /* Use Ci as temporary workspace for link lists [ */
+    Link = Ci ;
+    for (i = 0 ; i < nfr ; i++)
+    {
+       Link [i] = EMPTY ;
+    }
+
+    flops = 0 ;                        /* flop count upper bound */
+
+    for (chain = 0 ; chain < nchains ; chain++)
+    {
+       double fsize ;
+       f1 = Chain_start [chain] ;
+       f2 = Chain_start [chain+1] - 1 ;
+
+       /* allocate frontal matrix working array (C, L, and U) */
+       dr = Chain_maxrows [chain] ;
+       dc = Chain_maxcols [chain] ;
+       fsize =
+             nb*nb         /* LU is nb-by-nb */
+           + dr*nb         /* L is dr-by-nb */
+           + nb*dc         /* U is nb-by-dc, stored by rows */
+           + dr*dc ;       /* C is dr by dc */
+       dtail_usage += DUNITS (Entry, fsize) ;
+       dmax_usage = MAX (dmax_usage, dhead_usage + dtail_usage) ;
+
+       for (i = f1 ; i <= f2 ; i++)
+       {
+
+           /* get frontal matrix info */
+           fpivcol  = Front_npivcol [i] ; /* # candidate pivot columns */
+           fallrows = Fr_nrows [i] ;   /* all rows (not just Schur comp*/
+           fallcols = Fr_ncols [i] ;   /* all cols (not just Schur comp*/
+           parent = Front_parent [i] ; /* parent in column etree */
+           fpiv = MIN (fpivcol, fallrows) ;    /* # pivot rows and cols */
+           f = (double) fpiv ;
+           r = fallrows - fpiv ;               /* # rows in Schur comp. */
+           c = fallcols - fpiv ;               /* # cols in Schur comp. */
+
+           /* assemble all children of front i in column etree */
+           for (child = Link [i] ; child != EMPTY ; child = Link [child])
+           {
+               ASSERT (child >= 0 && child < i) ;
+               ASSERT (Front_parent [child] == i) ;
+               /* free the child element and remove it from tuple lists */
+               cp = MIN (Front_npivcol [child], Fr_nrows [child]) ;
+               cr = Fr_nrows [child] - cp ;
+               cc = Fr_ncols [child] - cp ;
+               ASSERT (cp >= 0 && cr >= 0 && cc >= 0) ;
+               dtail_usage -= ELEMENT_SIZE (cr, cc) ;
+
+           }
+
+           /* The flop count computed here is "canonical". */
+
+           /* factorize the frontal matrix */
+           flops += DIV_FLOPS * (f*r + (f-1)*f/2)  /* scale pivot columns */
+               /* f outer products: */
+               + MULTSUB_FLOPS * (f*r*c + (r+c)*(f-1)*f/2 + (f-1)*f*(2*f-1)/6);
+
+           /* count nonzeros and memory usage in double precision */
+           dlf = (f*f-f)/2 + f*r ;             /* nz in L below diagonal */
+           duf = (f*f-f)/2 + f*c ;             /* nz in U above diagonal */
+           dlnz += dlf ;
+           dunz += duf ;
+
+           /* store f columns of L and f rows of U */
+           dhead_usage +=
+               DUNITS (Entry, dlf + duf)   /* numerical values (excl diag) */
+               + DUNITS (Int, r + c + f) ; /* indices (compressed) */
+
+           if (parent != EMPTY)
+           {
+               /* create new element and place in tuple lists */
+               dtail_usage += ELEMENT_SIZE (r, c) ;
+
+               /* place in link list of parent */
+               Link [i] = Link [parent] ;
+               Link [parent] = i ;
+           }
+
+           /* keep track of peak Numeric->Memory usage */
+           dmax_usage = MAX (dmax_usage, dhead_usage + dtail_usage) ;
+
+       }
+
+       /* free the current frontal matrix */
+       dtail_usage -= DUNITS (Entry, fsize) ;
+    }
+
+    dhead_usage = ceil (dhead_usage) ;
+    dmax_usage = ceil (dmax_usage) ;
+    Symbolic->num_mem_size_est = dhead_usage ;
+    Symbolic->num_mem_usage_est = dmax_usage ;
+    Symbolic->lunz_bound = dlnz + dunz - n_inner ;
+
+    /* ] done using Ci as workspace for Link array */
+
+    /* ---------------------------------------------------------------------- */
+    /* estimate total memory usage in UMFPACK_numeric */
+    /* ---------------------------------------------------------------------- */
+
+    UMF_set_stats (
+       Info,
+       Symbolic,
+       dmax_usage,             /* estimated peak size of Numeric->Memory */
+       dhead_usage,            /* estimated final size of Numeric->Memory */
+       flops,                  /* estimated "true flops" */
+       dlnz,                   /* estimated nz in L */
+       dunz,                   /* estimated nz in U */
+       dmaxfrsize,             /* estimated largest front size */
+       (double) n_col,         /* worst case Numeric->Upattern size */
+       (double) n_inner,       /* max possible pivots to be found */
+       (double) maxnrows,      /* estimated largest #rows in front */
+       (double) maxncols,      /* estimated largest #cols in front */
+       TRUE,                   /* assume scaling is to be performed */
+       prefer_diagonal,
+       ESTIMATE) ;
+
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    for (i = 0 ; i < nchains ; i++)
+    {
+       DEBUG2 (("Chain "ID" start "ID" end "ID" maxrows "ID" maxcols "ID"\n",
+               i, Chain_start [i], Chain_start [i+1] - 1,
+               Chain_maxrows [i], Chain_maxcols [i])) ;
+       UMF_dump_chain (Chain_start [i], Fr_parent, Fr_npivcol, Fr_nrows,
+           Fr_ncols, nfr) ;
+    }
+    fpivcol = 0 ;
+    for (i = 0 ; i < nfr ; i++)
+    {
+       fpivcol = MAX (fpivcol, Front_npivcol [i]) ;
+    }
+    DEBUG0 (("Max pivot cols in any front: "ID"\n", fpivcol)) ;
+    DEBUG1 (("Largest front: maxnrows "ID" maxncols "ID" dmaxfrsize %g\n",
+       maxnrows, maxncols, dmaxfrsize)) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* UMFPACK_symbolic was successful, return the object handle */
+    /* ---------------------------------------------------------------------- */
+
+    Symbolic->valid = SYMBOLIC_VALID ;
+    *SymbolicHandle = (void *) Symbolic ;
+
+    /* ---------------------------------------------------------------------- */
+    /* free workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* (6) The last of the workspace is free'd.  The final Symbolic object
+     * consists of 12 to 14 allocated objects.  Its final total size is lies
+     * roughly between 4*n and 13*n for a square matrix, which is all that is
+     * left of the memory allocated by this routine.  If an error occurs, the
+     * entire Symbolic object is free'd when this routine returns (the error
+     * return routine, below).
+     */
+
+    free_work (SW) ;
+
+    DEBUG0 (("(3)Symbolic UMF_malloc_count - init_count = "ID"\n",
+       UMF_malloc_count - init_count)) ;
+    ASSERT (UMF_malloc_count == init_count + 12
+       + (Symbolic->Esize != (Int *) NULL)
+       + (Symbolic->Diagonal_map != (Int *) NULL)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get the time used by UMFPACK_*symbolic */
+    /* ---------------------------------------------------------------------- */
+
+    umfpack_toc (stats) ;
+    Info [UMFPACK_SYMBOLIC_WALLTIME] = stats [0] ;
+    Info [UMFPACK_SYMBOLIC_TIME] = stats [1] ;
+
+    return (UMFPACK_OK) ;
+}
+
+
+/* ========================================================================== */
+/* === free_work ============================================================ */
+/* ========================================================================== */
+
+PRIVATE void free_work
+(
+    SWType *SW
+)
+{
+    if (SW)
+    {
+       SW->Rperm_2by2 = (Int *) UMF_free ((void *) SW->Rperm_2by2) ;
+       SW->InvRperm1 = (Int *) UMF_free ((void *) SW->InvRperm1) ;
+       SW->Rs = (double *) UMF_free ((void *) SW->Rs) ;
+       SW->Si = (Int *) UMF_free ((void *) SW->Si) ;
+       SW->Sp = (Int *) UMF_free ((void *) SW->Sp) ;
+       SW->Ci = (Int *) UMF_free ((void *) SW->Ci) ;
+       SW->Front_npivcol = (Int *) UMF_free ((void *) SW->Front_npivcol);
+       SW->Front_nrows = (Int *) UMF_free ((void *) SW->Front_nrows) ;
+       SW->Front_ncols = (Int *) UMF_free ((void *) SW->Front_ncols) ;
+       SW->Front_parent = (Int *) UMF_free ((void *) SW->Front_parent) ;
+       SW->Front_cols = (Int *) UMF_free ((void *) SW->Front_cols) ;
+       SW->Cperm1 = (Int *) UMF_free ((void *) SW->Cperm1) ;
+       SW->Rperm1 = (Int *) UMF_free ((void *) SW->Rperm1) ;
+       SW->InFront = (Int *) UMF_free ((void *) SW->InFront) ;
+    }
+}
+
+
+/* ========================================================================== */
+/* === error ================================================================ */
+/* ========================================================================== */
+
+/* Error return from UMFPACK_symbolic.  Free all allocated memory. */
+
+PRIVATE void error
+(
+    SymbolicType **Symbolic,
+    SWType *SW
+)
+{
+
+    free_work (SW) ;
+    UMFPACK_free_symbolic ((void **) Symbolic) ;
+    ASSERT (UMF_malloc_count == init_count) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_control.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_control.c
new file mode 100644 (file)
index 0000000..fdc614f
--- /dev/null
@@ -0,0 +1,387 @@
+/* ========================================================================== */
+/* === UMFPACK_report_control =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Prints the control settings.  See umfpack_report_control.h
+    for details.
+*/
+
+#include "umf_internal.h"
+
+GLOBAL void UMFPACK_report_control
+(
+    const double Control [UMFPACK_CONTROL]
+)
+{
+    Int prl, nb, irstep, strategy, scale, s ;
+    double drow, dcol, relpt, relpt2, alloc_init, front_alloc_init, amd_alpha,
+       tol, force_fixQ, droptol, aggr ;
+
+    prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ;
+
+    if (prl < 2)
+    {
+       /* default is to print nothing */
+       return ;
+    }
+
+    PRINTF (("\n%s, Control:\n\n", UMFPACK_VERSION)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* run-time options */
+    /* ---------------------------------------------------------------------- */
+
+    /* This is a "run-time" option because all four umfpack_* versions */
+    /* compiled into the UMFPACK library. */
+
+#ifdef DINT
+    PRINTF (("    Matrix entry defined as: double\n")) ;
+    PRINTF (("    Int (generic integer) defined as: int\n")) ;
+#endif
+#ifdef DLONG
+    PRINTF (("    Matrix entry defined as: double\n")) ;
+    PRINTF (("    Int (generic integer) defined as: long\n")) ;
+#endif
+#ifdef ZINT
+    PRINTF (("    Matrix entry defined as: double complex\n")) ;
+    PRINTF (("    Int (generic integer) defined as: int\n")) ;
+#endif
+#ifdef ZLONG
+    PRINTF (("    Matrix entry defined as: double complex\n")) ;
+    PRINTF (("    Int (generic integer) defined as: long\n")) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* printing level */
+    /* ---------------------------------------------------------------------- */
+
+    PRINTF (("\n    "ID": print level: "ID"\n",
+       (Int) INDEX (UMFPACK_PRL), prl)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* dense row/col parameters */
+    /* ---------------------------------------------------------------------- */
+
+    drow = GET_CONTROL (UMFPACK_DENSE_ROW, UMFPACK_DEFAULT_DENSE_ROW) ;
+    dcol = GET_CONTROL (UMFPACK_DENSE_COL, UMFPACK_DEFAULT_DENSE_COL) ;
+
+    PRINTF (("    "ID": dense row parameter:    %g\n",
+       (Int) INDEX (UMFPACK_DENSE_ROW), drow)) ;
+    PRINTF (("        \"dense\" rows have    > max (16, (%g)*16*sqrt(n_col)"
+       " entries)\n", drow)) ;
+    PRINTF (("    "ID": dense column parameter: %g\n",
+       (Int) INDEX (UMFPACK_DENSE_COL), dcol)) ;
+    PRINTF (("        \"dense\" columns have > max (16, (%g)*16*sqrt(n_row)"
+       " entries)\n", dcol)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* pivot tolerance */
+    /* ---------------------------------------------------------------------- */
+
+    relpt = GET_CONTROL (UMFPACK_PIVOT_TOLERANCE,
+       UMFPACK_DEFAULT_PIVOT_TOLERANCE) ;
+    relpt = MAX (0.0, MIN (relpt, 1.0)) ;
+    PRINTF (("    "ID": pivot tolerance: %g\n",
+       (Int) INDEX (UMFPACK_PIVOT_TOLERANCE), relpt)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* block size */
+    /* ---------------------------------------------------------------------- */
+
+    nb = GET_CONTROL (UMFPACK_BLOCK_SIZE, UMFPACK_DEFAULT_BLOCK_SIZE) ;
+    nb = MAX (1, nb) ;
+    PRINTF (("    "ID": block size for dense matrix kernels: "ID"\n",
+       (Int) INDEX (UMFPACK_BLOCK_SIZE), nb)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* strategy */
+    /* ---------------------------------------------------------------------- */
+
+    strategy = GET_CONTROL (UMFPACK_STRATEGY, UMFPACK_DEFAULT_STRATEGY) ;
+    if (strategy < UMFPACK_STRATEGY_AUTO
+     || strategy > UMFPACK_STRATEGY_SYMMETRIC)
+    {
+       strategy = UMFPACK_STRATEGY_AUTO ;
+    }
+
+    PRINTF (("    "ID": strategy: "ID,
+       (Int) INDEX (UMFPACK_STRATEGY), strategy)) ;
+
+    if (strategy == UMFPACK_STRATEGY_SYMMETRIC)
+    {
+       PRINTF ((" (symmetric)\n"
+       "        Q = AMD (A+A'), Q not refined during numerical\n"
+       "        factorization, and diagonal pivoting (P=Q') attempted.\n")) ;
+    }
+    else if (strategy == UMFPACK_STRATEGY_UNSYMMETRIC)
+    {
+       PRINTF ((" (unsymmetric)\n"
+       "        Q = COLAMD (A), Q refined during numerical\n"
+       "        factorization, and no attempt at diagonal pivoting.\n")) ;
+    }
+    else if (strategy == UMFPACK_STRATEGY_2BY2)
+    {
+       PRINTF ((" (symmetric, with 2-by-2 block pivoting)\n"
+       "        P2 = row permutation that tries to place large entries on\n"
+       "        the diagonal.  Q = AMD (P2*A+(P2*A)'), Q not refined during\n"
+       "        numerical factorization, attempt to select pivots from the\n"
+       "        diagonal of P2*A.\n")) ;
+    }
+    else /* auto strategy */
+    {
+       strategy = UMFPACK_STRATEGY_AUTO ;
+       PRINTF ((" (auto)\n")) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* initial allocation parameter */
+    /* ---------------------------------------------------------------------- */
+
+    alloc_init = GET_CONTROL (UMFPACK_ALLOC_INIT, UMFPACK_DEFAULT_ALLOC_INIT) ;
+    if (alloc_init >= 0)
+    {
+       PRINTF (("    "ID": initial allocation ratio: %g\n",
+       (Int) INDEX (UMFPACK_ALLOC_INIT), alloc_init)) ;
+    }
+    else
+    {
+       s = -alloc_init ;
+       s = MAX (1, s) ;
+       PRINTF (("    "ID": initial allocation (in Units): "ID"\n",
+       (Int) INDEX (UMFPACK_ALLOC_INIT), s)) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* maximum iterative refinement steps */
+    /* ---------------------------------------------------------------------- */
+
+    irstep = GET_CONTROL (UMFPACK_IRSTEP, UMFPACK_DEFAULT_IRSTEP) ;
+    irstep = MAX (0, irstep) ;
+    PRINTF (("    "ID": max iterative refinement steps: "ID"\n",
+       (Int) INDEX (UMFPACK_IRSTEP), irstep)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* 2-by-2 pivot tolerance */
+    /* ---------------------------------------------------------------------- */
+
+    tol = GET_CONTROL (UMFPACK_2BY2_TOLERANCE, UMFPACK_DEFAULT_2BY2_TOLERANCE) ;
+    tol = MAX (0.0, MIN (tol, 1.0)) ;
+    PRINTF (("    "ID": 2-by-2 pivot tolerance: %g\n",
+       (Int) INDEX (UMFPACK_2BY2_TOLERANCE), tol)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* force fixQ */
+    /* ---------------------------------------------------------------------- */
+
+    force_fixQ = GET_CONTROL (UMFPACK_FIXQ, UMFPACK_DEFAULT_FIXQ) ;
+    PRINTF (("    "ID": Q fixed during numerical factorization: %g ",
+       (Int) INDEX (UMFPACK_FIXQ), force_fixQ)) ;
+    if (force_fixQ > 0)
+    {
+       PRINTF (("(yes)\n")) ;
+    }
+    else if (force_fixQ < 0)
+    {
+       PRINTF (("(no)\n")) ;
+    }
+    else
+    {
+       PRINTF (("(auto)\n")) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* AMD parameters */
+    /* ---------------------------------------------------------------------- */
+
+    amd_alpha = GET_CONTROL (UMFPACK_AMD_DENSE, UMFPACK_DEFAULT_AMD_DENSE) ;
+    PRINTF (("    "ID": AMD dense row/col parameter:    %g\n",
+       (Int) INDEX (UMFPACK_AMD_DENSE), amd_alpha)) ;
+    if (amd_alpha < 0)
+    {
+       PRINTF (("       no \"dense\" rows/columns\n")) ;
+    }
+    else
+    {
+       PRINTF (("       \"dense\" rows/columns have > max (16, (%g)*sqrt(n))"
+           " entries\n", amd_alpha)) ;
+    }
+    PRINTF (("        Only used if the AMD ordering is used.\n")) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* pivot tolerance for symmetric pivoting */
+    /* ---------------------------------------------------------------------- */
+
+    relpt2 = GET_CONTROL (UMFPACK_SYM_PIVOT_TOLERANCE,
+       UMFPACK_DEFAULT_SYM_PIVOT_TOLERANCE) ;
+    relpt2 = MAX (0.0, MIN (relpt2, 1.0)) ;
+    PRINTF (("    "ID": diagonal pivot tolerance: %g\n"
+       "        Only used if diagonal pivoting is attempted.\n",
+       (Int) INDEX (UMFPACK_SYM_PIVOT_TOLERANCE), relpt2)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* scaling */
+    /* ---------------------------------------------------------------------- */
+
+    scale = GET_CONTROL (UMFPACK_SCALE, UMFPACK_DEFAULT_SCALE) ;
+    if (scale != UMFPACK_SCALE_NONE && scale != UMFPACK_SCALE_MAX)
+    {
+       scale = UMFPACK_DEFAULT_SCALE ;
+    }
+    PRINTF (("    "ID": scaling: "ID, (Int) INDEX (UMFPACK_SCALE), scale)) ;
+    if (scale == UMFPACK_SCALE_NONE)
+    {
+       PRINTF ((" (no)")) ;
+    }
+    else if (scale == UMFPACK_SCALE_SUM)
+    {
+       PRINTF ((" (divide each row by sum of abs. values in each row)")) ;
+    }
+    else if (scale == UMFPACK_SCALE_MAX)
+    {
+       PRINTF ((" (divide each row by max. abs. value in each row)")) ;
+    }
+    PRINTF (("\n")) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* frontal matrix allocation parameter */
+    /* ---------------------------------------------------------------------- */
+
+    front_alloc_init = GET_CONTROL (UMFPACK_FRONT_ALLOC_INIT,
+       UMFPACK_DEFAULT_FRONT_ALLOC_INIT) ;
+    front_alloc_init = MIN (1.0, front_alloc_init) ;
+    if (front_alloc_init >= 0)
+    {
+       PRINTF (("    "ID": frontal matrix allocation ratio: %g\n",
+       (Int) INDEX (UMFPACK_FRONT_ALLOC_INIT), front_alloc_init)) ;
+    }
+    else
+    {
+       s = -front_alloc_init ;
+       s = MAX (1, s) ;
+       PRINTF (("    "ID": initial frontal matrix size (# of Entry's): "ID"\n",
+       (Int) INDEX (UMFPACK_FRONT_ALLOC_INIT), s)) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* 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))) ;
+
+#if defined (USE_NO_BLAS)
+    PRINTF (("none.  UMFPACK will be slow.\n")) ;
+#elif defined (USE_C_BLAS)
+    PRINTF (("C-BLAS.\n")) ;
+#elif defined (USE_MATLAB_BLAS)
+    PRINTF (("built-in MATLAB BLAS (ATLAS).\n")) ;
+#elif defined (USE_SUNPERF_BLAS)
+    PRINTF (("Sun Performance Library BLAS.\n")) ;
+#elif defined (USE_SCSL_BLAS)
+    PRINTF (("SGI SCSL BLAS.\n")) ;
+#elif defined (USE_FORTRAN_BLAS)
+    PRINTF (("Fortran BLAS.\n")) ;
+#endif
+
+#ifdef MATLAB_MEX_FILE
+#ifdef NUTIL
+    PRINTF (("    "ID": compiled for MATLAB"
+    " (uses mxMalloc, mxFree, mxRealloc, and mexPrintf)\n",
+       (Int) INDEX (UMFPACK_COMPILED_FOR_MATLAB))) ;
+#else
+    PRINTF (("    "ID": compiled for MATLAB"
+    " (uses utMalloc, utFree, utRealloc, and mexPrintf)\n",
+       (Int) INDEX (UMFPACK_COMPILED_FOR_MATLAB))) ;
+#endif
+#else
+#ifdef MATHWORKS
+    PRINTF (("    "ID": compiled for MATLAB, using internal utility routines\n"
+    "    (uses utMalloc, utFree, utRealloc, and utPrintf)\n",
+       (Int) INDEX (UMFPACK_COMPILED_FOR_MATLAB))) ;
+    PRINTF (("    (complex version uses utDivideComplex, utFdlibm_hypot)\n")) ;
+#else
+    PRINTF (("    "ID": compiled for ANSI C"
+    " (uses malloc, free, realloc, and printf)\n",
+       (Int) INDEX (UMFPACK_COMPILED_FOR_MATLAB))) ;
+#endif
+#endif
+
+#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))) ;
+#ifdef MATLAB_MEX_FILE
+    PRINTF (("Uses mxAssert.\n")) ;
+#else
+#ifdef MATHWORKS
+    PRINTF (("Uses utAssert.\n")) ;
+#else
+    PRINTF (("Uses ANSI C assert.\n")) ;
+#endif
+#endif
+#else
+    PRINTF (("    "ID": compiled for normal operation (debugging disabled)\n",
+       (Int) INDEX (UMFPACK_COMPILED_IN_DEBUG_MODE))) ;
+#endif
+
+    PRINTF (("    computer/operating system: %s\n", UMFPACK_ARCHITECTURE)) ;
+    PRINTF (("    size of int: %g long: %g Int: %g pointer: %g"
+       " double: %g Entry: %g (in bytes)\n\n", (double) sizeof (int),
+       (double) sizeof (long), (double) sizeof (Int),
+       (double) sizeof (void *), (double) sizeof (double),
+       (double) sizeof (Entry))) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_info.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_info.c
new file mode 100644 (file)
index 0000000..4c806d2
--- /dev/null
@@ -0,0 +1,616 @@
+/* ========================================================================== */
+/* === UMFPACK_report_info ================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Prints the Info array.  See umfpack_report_info.h for
+    details.
+*/
+
+#include "umf_internal.h"
+
+#define PRINT_INFO(format,x) \
+{ \
+    if (SCALAR_IS_NAN (x) || (!SCALAR_IS_LTZERO (x))) \
+    { \
+       PRINTF ((format, x)) ; \
+    } \
+}
+
+/* RATIO macro uses a double relop, but ignore NaN case: */
+#define RATIO(a,b,c) (((b) == 0) ? (c) : (((double) a)/((double) b)))
+
+/* ========================================================================== */
+/* === print_ratio ========================================================== */
+/* ========================================================================== */
+
+PRIVATE void print_ratio
+(
+    char *what,
+    char *format,
+    double estimate,
+    double actual
+)
+{
+    if (estimate < 0 && actual < 0)    /* double relop, but ignore Nan case */
+    {
+       return ;
+    }
+    PRINTF (("    %-27s", what)) ;
+    if (estimate >= 0)                 /* double relop, but ignore Nan case */
+    {
+       PRINTF ((format, estimate)) ;
+    }
+    else
+    {
+       PRINTF (("                    -")) ;
+    }
+    if (actual >= 0)                   /* double relop, but ignore Nan case */
+    {
+       PRINTF ((format, actual)) ;
+    }
+    else
+    {
+       PRINTF (("                    -")) ;
+    }
+    if (estimate >= 0 && actual >= 0)  /* double relop, but ignore Nan case */
+    {
+       PRINTF ((" %5.0f%%\n", 100 * RATIO (actual, estimate, 1))) ;
+    }
+    else
+    {
+       PRINTF (("      -\n")) ;
+    }
+}
+
+/* ========================================================================== */
+/* === UMFPACK_report_info ================================================== */
+/* ========================================================================== */
+
+GLOBAL void UMFPACK_report_info
+(
+    const double Control [UMFPACK_CONTROL],
+    const double Info [UMFPACK_INFO]
+)
+{
+
+    double lnz_est, unz_est, lunz_est, lnz, unz, lunz, tsym, tnum, fnum, tsolve,
+       fsolve, ttot, ftot, twsym, twnum, twsolve, twtot, n2 ;
+    Int n_row, n_col, n_inner, prl, is_sym ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get control settings and status to determine what to print */
+    /* ---------------------------------------------------------------------- */
+
+    prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ;
+
+    if (!Info || prl < 2)
+    {
+       /* no output generated if Info is (double *) NULL */
+       /* or if prl is less than 2 */
+       return ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* print umfpack version */
+    /* ---------------------------------------------------------------------- */
+
+    PRINTF (("\n%s, Info:\n", UMFPACK_VERSION)) ;
+
+#ifndef NDEBUG
+    PRINTF ((
+"**** Debugging enabled (UMFPACK will be exceedingly slow!) *****************\n"
+    )) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* print run-time options */
+    /* ---------------------------------------------------------------------- */
+
+#ifdef DINT
+    PRINTF (("    matrix entry defined as:          double\n")) ;
+    PRINTF (("    Int (generic integer) defined as: int\n")) ;
+#endif
+#ifdef DLONG
+    PRINTF (("    matrix entry defined as:          double\n")) ;
+    PRINTF (("    Int (generic integer) defined as: long\n")) ;
+#endif
+#ifdef ZINT
+    PRINTF (("    matrix entry defined as:          double complex\n")) ;
+    PRINTF (("    Int (generic integer) defined as: int\n")) ;
+#endif
+#ifdef ZLONG
+    PRINTF (("    matrix entry defined as:          double complex\n")) ;
+    PRINTF (("    Int (generic integer) defined as: long\n")) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* print compile-time options */
+    /* ---------------------------------------------------------------------- */
+
+    PRINTF (("    BLAS library used:                ")) ;
+
+#if defined (USE_NO_BLAS)
+    PRINTF (("none.  UMFPACK will be slow.\n")) ;
+#elif defined (USE_C_BLAS)
+    PRINTF (("C-BLAS.\n")) ;
+#elif defined (USE_MATLAB_BLAS)
+    PRINTF (("built-in MATLAB BLAS.\n")) ;
+#elif defined (USE_SUNPERF_BLAS)
+    PRINTF (("Sun Performance Library BLAS.\n")) ;
+#elif defined (USE_SCSL_BLAS)
+    PRINTF (("SGI SCSL BLAS.\n")) ;
+#elif defined (USE_FORTRAN_BLAS)
+    PRINTF (("Fortran BLAS.\n")) ;
+#endif
+
+    PRINTF (("    MATLAB:                           ")) ;
+#ifdef MATLAB_MEX_FILE
+    PRINTF (("yes.\n")) ;
+#else
+#ifdef MATHWORKS
+    PRINTF (("yes (using internal ut* routines).\n")) ;
+#else
+    PRINTF (("no.\n")) ;
+#endif
+#endif
+
+    PRINTF (("    CPU timer:                        ")) ;
+#ifdef 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 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) ;
+
+    if (tnum > 0 && fnum > 0)
+    {
+       PRINT_INFO (
+          "    numeric factorization mflops (CPU time):       %.2f\n",
+          1e-6 * fnum / tnum) ;
+    }
+    if (twnum > 0 && fnum > 0)
+    {
+       PRINT_INFO (
+          "    numeric factorization mflops (wallclock):      %.2f\n",
+          1e-6 * fnum / twnum) ;
+    }
+
+    ttot = EMPTY ;
+    ftot = fnum ;
+    if (tsym >= 0 && tnum >= 0)
+    {
+       ttot = tsym + tnum ;
+       PRINT_INFO ("    symbolic + numeric CPU time (sec):             %.2f\n",
+           ttot) ;
+       if (ftot > 0 && ttot > 0)
+       {
+           PRINT_INFO (
+               "    symbolic + numeric mflops (CPU time):          %.2f\n",
+               1e-6 * ftot / ttot) ;
+       }
+    }
+
+    twtot = EMPTY ;
+    if (twsym >= 0 && twnum >= 0)
+    {
+       twtot = twsym + twnum ;
+       PRINT_INFO ("    symbolic + numeric wall clock time (sec):      %.2f\n",
+           twtot) ;
+       if (ftot > 0 && twtot > 0)
+       {
+           PRINT_INFO (
+               "    symbolic + numeric mflops (wall clock):        %.2f\n",
+               1e-6 * ftot / twtot) ;
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* solve */
+    /* ---------------------------------------------------------------------- */
+
+    tsolve = Info [UMFPACK_SOLVE_TIME] ;
+    twsolve = Info [UMFPACK_SOLVE_WALLTIME] ;
+    fsolve = Info [UMFPACK_SOLVE_FLOPS] ;
+
+    PRINT_INFO ("\n    solve flops:                                   %.5e\n",
+       fsolve) ;
+    PRINT_INFO ("    iterative refinement steps taken:              %.0f\n",
+       Info [UMFPACK_IR_TAKEN]) ;
+    PRINT_INFO ("    iterative refinement steps attempted:          %.0f\n",
+       Info [UMFPACK_IR_ATTEMPTED]) ;
+    PRINT_INFO ("    sparse backward error omega1:                  %.2e\n",
+       Info [UMFPACK_OMEGA1]) ;
+    PRINT_INFO ("    sparse backward error omega2:                  %.2e\n",
+       Info [UMFPACK_OMEGA2]) ;
+    PRINT_INFO ("    solve CPU time (sec):                          %.2f\n",
+       tsolve) ;
+    PRINT_INFO ("    solve wall clock time (sec):                   %.2f\n",
+       twsolve) ;
+    if (fsolve > 0 && tsolve > 0)
+    {
+       PRINT_INFO (
+           "    solve mflops (CPU time):                       %.2f\n",
+           1e-6 * fsolve / tsolve) ;
+    }
+    if (fsolve > 0 && twsolve > 0)
+    {
+       PRINT_INFO (
+           "    solve mflops (wall clock time):                %.2f\n",
+           1e-6 * fsolve / twsolve) ;
+    }
+
+    if (ftot >= 0 && fsolve >= 0)
+    {
+       ftot += fsolve ;
+       PRINT_INFO (
+       "\n    total symbolic + numeric + solve flops:        %.5e\n", ftot) ;
+    }
+
+    if (tsolve >= 0)
+    {
+       if (ttot >= 0 && ftot >= 0)
+       {
+           ttot += tsolve ;
+           PRINT_INFO (
+               "    total symbolic + numeric + solve CPU time:     %.2f\n",
+               ttot) ;
+           if (ftot > 0 && ttot > 0)
+           {
+               PRINT_INFO (
+               "    total symbolic + numeric + solve mflops (CPU): %.2f\n",
+               1e-6 * ftot / ttot) ;
+           }
+       }
+    }
+
+    if (twsolve >= 0)
+    {
+       if (twtot >= 0 && ftot >= 0)
+       {
+           twtot += tsolve ;
+           PRINT_INFO (
+               "    total symbolic+numeric+solve wall clock time:  %.2f\n",
+               twtot) ;
+           if (ftot > 0 && twtot > 0)
+           {
+               PRINT_INFO (
+               "    total symbolic+numeric+solve mflops(wallclock) %.2f\n",
+               1e-6 * ftot / twtot) ;
+           }
+       }
+    }
+    PRINTF (("\n")) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_matrix.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_matrix.c
new file mode 100644 (file)
index 0000000..d5066a4
--- /dev/null
@@ -0,0 +1,205 @@
+/* ========================================================================== */
+/* === UMFPACK_report_matrix ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Prints a column or row-oriented matrix.  See
+    umfpack_report_matrix.h for details.
+*/
+
+#include "umf_internal.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+
+GLOBAL Int UMFPACK_report_matrix
+(
+    Int n_row,
+    Int n_col,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const double Ax [ ],
+#ifdef COMPLEX
+    const double Az [ ],
+#endif
+    Int col_form,              /* 1: column form, 0: row form */
+    const double Control [UMFPACK_CONTROL]
+)
+{
+    Int prl, i, k, length, ilast, p, nz, prl1, p1, p2, n, n_i, do_values ;
+    char *vector, *index ;
+    Entry a ;
+
+    /* ---------------------------------------------------------------------- */
+    /* determine the form, and check if inputs exist */
+    /* ---------------------------------------------------------------------- */
+
+    prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ;
+
+    if (prl <= 2)
+    {
+       return (UMFPACK_OK) ;
+    }
+
+    if (col_form)
+    {
+       vector = "column" ;     /* column vectors */
+       index = "row" ;         /* with row indices */
+       n = n_col ;
+       n_i = n_row ;
+    }
+    else
+    {
+       vector = "row" ;        /* row vectors */
+       index = "column" ;      /* with column indices */
+       n = n_row ;
+       n_i = n_col ;
+    }
+
+    PRINTF (("%s-form matrix, n_row "ID" n_col "ID", ", vector, n_row, n_col)) ;
+
+    if (n_row <= 0 || n_col <= 0)
+    {
+       PRINTF (("ERROR: n_row <= 0 or n_col <= 0\n\n")) ;
+       return (UMFPACK_ERROR_n_nonpositive) ;
+    }
+
+    if (!Ap)
+    {
+       PRINTF (("ERROR: Ap missing\n\n")) ;
+       return (UMFPACK_ERROR_argument_missing) ;
+    }
+
+    nz = Ap [n] ;
+    PRINTF (("nz = "ID". ", nz)) ;
+    if (nz < 0)
+    {
+       PRINTF (("ERROR: number of entries < 0\n\n")) ;
+       return (UMFPACK_ERROR_invalid_matrix) ;
+    }
+
+    if (Ap [0] != 0)
+    {
+       PRINTF (("ERROR: Ap ["ID"] = "ID" must be "ID"\n\n",
+           (Int) INDEX (0), INDEX (Ap [0]), (Int) INDEX (0))) ;
+       return (UMFPACK_ERROR_invalid_matrix) ;
+    }
+
+    if (!Ai)
+    {
+       PRINTF (("ERROR: Ai missing\n\n")) ;
+       return (UMFPACK_ERROR_argument_missing) ;
+    }
+
+#ifdef COMPLEX
+    do_values = Ax && Az ;
+#else
+    do_values = Ax != (double *) NULL ;
+#endif
+
+    PRINTF4 (("\n")) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check the row/column pointers, Ap */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = 0 ; k < n ; k++)
+    {
+       if (Ap [k] < 0)
+       {
+           PRINTF (("ERROR: Ap ["ID"] < 0\n\n", INDEX (k))) ;
+           return (UMFPACK_ERROR_invalid_matrix) ;
+       }
+       if (Ap [k] > nz)
+       {
+           PRINTF (("ERROR: Ap ["ID"] > size of Ai\n\n", INDEX (k))) ;
+           return (UMFPACK_ERROR_invalid_matrix) ;
+       }
+    }
+
+    for (k = 0 ; k < n ; k++)
+    {
+       length = Ap [k+1] - Ap [k] ;
+       if (length < 0)
+       {
+           PRINTF (("ERROR: # entries in %s "ID" is < 0\n\n",
+               vector, INDEX (k))) ;
+           return (UMFPACK_ERROR_invalid_matrix) ;
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* print each vector */
+    /* ---------------------------------------------------------------------- */
+
+    prl1 = prl ;
+
+    for (k = 0 ; k < n ; k++)
+    {
+       /* if prl is 4, print the first 10 entries of the first 10 vectors */
+       if (k < 10)
+       {
+           prl = prl1 ;
+       }
+       /* get the vector pointers */
+       p1 = Ap [k] ;
+       p2 = Ap [k+1] ;
+       length = p2 - p1 ;
+       PRINTF4 (("\n    %s "ID": start: "ID" end: "ID" entries: "ID"\n",
+           vector, INDEX (k), p1, p2-1, length)) ;
+       ilast = EMPTY ;
+       for (p = p1 ; p < p2 ; p++)
+       {
+           i = Ai [p] ;
+           PRINTF4 (("\t%s "ID" ", index, INDEX (i))) ;
+           if (do_values && prl >= 4)
+           {
+               PRINTF ((":")) ;
+               ASSIGN (a, Ax [p], Az [p]) ;
+               PRINT_ENTRY (a) ;
+           }
+           if (i < 0 || i >= n_i)
+           {
+               PRINTF ((" ERROR: %s index "ID" out of range in %s "ID"\n\n",
+                   index, INDEX (i), vector, INDEX (k))) ;
+               return (UMFPACK_ERROR_invalid_matrix) ;
+           }
+           if (i <= ilast)
+           {
+               PRINTF ((" ERROR: %s index "ID" out of order (or duplicate) in "
+                   "%s "ID"\n\n", index, INDEX (i), vector, INDEX (k))) ;
+               return (UMFPACK_ERROR_invalid_matrix) ;
+           }
+           PRINTF4 (("\n")) ;
+           /* truncate printout, but continue to check matrix */
+           if (prl == 4 && (p - p1) == 9 && length > 10)
+           {
+               PRINTF4 (("\t...\n")) ;
+               prl-- ;
+           }
+           ilast = i ;
+       }
+       /* truncate printout, but continue to check matrix */
+       if (prl == 4 && k == 9 && n > 10)
+       {
+           PRINTF4 (("\n    ...\n")) ;
+           prl-- ;
+       }
+    }
+    prl = prl1 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* return the status of the matrix */
+    /* ---------------------------------------------------------------------- */
+
+    PRINTF4 (("    %s-form matrix ", vector)) ;
+    PRINTF (("OK\n\n")) ;
+
+    return (UMFPACK_OK) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_numeric.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_numeric.c
new file mode 100644 (file)
index 0000000..c66a2c6
--- /dev/null
@@ -0,0 +1,664 @@
+/* ========================================================================== */
+/* === UMFPACK_report_numeric =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Prints the Numeric object.
+    See umfpack_report_numeric.h for details.
+
+    Dynamic memory usage:  Allocates a size n*sizeof(Int) workspace via a single
+    call to UMF_malloc and then frees all of it via UMF_free on return.  The
+    workspace is not allocated if an early error return occurs before the
+    workspace is needed.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_numeric.h"
+#include "umf_report_perm.h"
+#include "umf_report_vector.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+
+
+PRIVATE Int report_L
+(
+    NumericType *Numeric,
+    Int Pattern [ ],
+    Int prl
+) ;
+
+
+PRIVATE Int report_U
+(
+    NumericType *Numeric,
+    Int Pattern [ ],
+    Int prl
+) ;
+
+/* ========================================================================== */
+/* === UMFPACK_report_numeric =============================================== */
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_report_numeric
+(
+    void *NumericHandle,
+    const double Control [UMFPACK_CONTROL]
+)
+{
+    Int prl, *W, nn, n_row, n_col, n_inner, num_fixed_size, numeric_size,
+       npiv ;
+    NumericType *Numeric ;
+
+    prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ;
+
+    if (prl <= 2)
+    {
+       return (UMFPACK_OK) ;
+    }
+
+    PRINTF (("Numeric object:  ")) ;
+
+    Numeric = (NumericType *) NumericHandle ;
+    if (!UMF_valid_numeric (Numeric))
+    {
+       PRINTF (("ERROR: LU factors invalid\n\n")) ;
+       return (UMFPACK_ERROR_invalid_Numeric_object) ;
+    }
+
+    n_row = Numeric->n_row ;
+    n_col = Numeric->n_col ;
+    nn = MAX (n_row, n_col) ;
+    n_inner = MIN (n_row, n_col) ;
+    npiv = Numeric->npiv ;
+
+    DEBUG1 (("n_row "ID" n_col "ID" nn "ID" n_inner "ID" npiv "ID"\n",
+       n_row, n_col, nn, n_inner, npiv)) ;
+
+    /* size of Numeric object, except Numeric->Memory and Numeric->Upattern */
+    /* see also UMF_set_stats */
+    num_fixed_size =
+       UNITS (NumericType, 1)          /* Numeric structure */
+       + UNITS (Entry, n_inner+1)      /* D */
+       + UNITS (Int, n_row+1)          /* Rperm */
+       + UNITS (Int, n_col+1)          /* Cperm */
+       + 6 * UNITS (Int, npiv+1)       /* Lpos, Uilen, Uip, Upos, Lilen, Lip */
+       + ((Numeric->scale != UMFPACK_SCALE_NONE) ?
+               UNITS (Entry, n_row) : 0) ; /* Rs */
+
+    DEBUG1 (("num fixed size: "ID"\n", num_fixed_size)) ;
+    DEBUG1 (("Numeric->size "ID"\n", Numeric->size)) ;
+    DEBUG1 (("ulen units "ID"\n", UNITS (Int, Numeric->ulen))) ;
+
+    /* size of Numeric->Memory is Numeric->size */
+    /* size of Numeric->Upattern is Numeric->ulen */
+    numeric_size = num_fixed_size + Numeric->size
+       + UNITS (Int, Numeric->ulen) ;
+
+    DEBUG1 (("numeric total size "ID"\n", numeric_size)) ;
+
+    if (prl >= 4)
+    {
+       PRINTF (("\n    n_row: "ID"  n_col: "ID"\n", n_row, n_col)) ;
+
+       PRINTF (("    relative pivot tolerance used:              %g\n",
+           Numeric->relpt)) ;
+       PRINTF (("    relative symmetric pivot tolerance used:    %g\n",
+           Numeric->relpt2)) ;
+
+       PRINTF (("    matrix scaled: ")) ;
+       if (Numeric->scale == UMFPACK_SCALE_NONE)
+       {
+           PRINTF (("no")) ;
+       }
+       else if (Numeric->scale == UMFPACK_SCALE_SUM)
+       {
+           PRINTF (("yes (divided each row by sum abs value in each row)\n")) ;
+           PRINTF (("    minimum sum (abs (rows of A)):              %.5e\n",
+               Numeric->rsmin)) ;
+           PRINTF (("    maximum sum (abs (rows of A)):              %.5e",
+               Numeric->rsmax)) ;
+       }
+       else if (Numeric->scale == UMFPACK_SCALE_MAX)
+       {
+           PRINTF (("yes (divided each row by max abs value in each row)\n")) ;
+           PRINTF (("    minimum max (abs (rows of A)):              %.5e\n",
+               Numeric->rsmin)) ;
+           PRINTF (("    maximum max (abs (rows of A)):              %.5e",
+               Numeric->rsmax)) ;
+       }
+       PRINTF (("\n")) ;
+
+       PRINTF (("    initial allocation parameter used:          %g\n",
+           Numeric->alloc_init)) ;
+       PRINTF (("    frontal matrix allocation parameter used:   %g\n",
+           Numeric->front_alloc_init)) ;
+       PRINTF (("    final total size of Numeric object (Units): "ID"\n",
+           numeric_size)) ;
+       PRINTF (("    final total size of Numeric object (MBytes): %.1f\n",
+           MBYTES (numeric_size))) ;
+       PRINTF (("    peak size of variable-size part (Units):    "ID"\n",
+           Numeric->max_usage)) ;
+       PRINTF (("    peak size of variable-size part (MBytes):   %.1f\n",
+           MBYTES (Numeric->max_usage))) ;
+       PRINTF (("    largest actual frontal matrix size:         "ID"\n",
+           Numeric->maxfrsize)) ;
+       PRINTF (("    memory defragmentations:                    "ID"\n",
+           Numeric->ngarbage)) ;
+       PRINTF (("    memory reallocations:                       "ID"\n",
+           Numeric->nrealloc)) ;
+       PRINTF (("    costly memory reallocations:                "ID"\n",
+           Numeric->ncostly)) ;
+       PRINTF (("    entries in compressed pattern (L and U):    "ID"\n",
+           Numeric->isize)) ;
+       PRINTF (("    number of nonzeros in L (excl diag):        "ID"\n",
+           Numeric->lnz)) ;
+       PRINTF (("    number of entries stored in L (excl diag):  "ID"\n",
+           Numeric->nLentries)) ;
+       PRINTF (("    number of nonzeros in U (excl diag):        "ID"\n",
+           Numeric->unz)) ;
+       PRINTF (("    number of entries stored in U (excl diag):  "ID"\n",
+           Numeric->nUentries)) ;
+       PRINTF (("    factorization floating-point operations:    %g\n",
+           Numeric->flops)) ;
+       PRINTF (("    number of nonzeros on diagonal of U:        "ID"\n",
+           Numeric->nnzpiv)) ;
+       PRINTF (("    min abs. value on diagonal of U:            %.5e\n",
+           Numeric->min_udiag)) ;
+       PRINTF (("    max abs. value on diagonal of U:            %.5e\n",
+           Numeric->max_udiag)) ;
+       PRINTF (("    reciprocal condition number estimate:       %.2e\n",
+           Numeric->rcond)) ;
+    }
+
+    W = (Int *) UMF_malloc (nn, sizeof (Int)) ;
+    if (!W)
+    {
+       PRINTF ((" ERROR: out of memory to check Numeric object\n\n")) ;
+       return (UMFPACK_ERROR_out_of_memory) ;
+    }
+
+    if (Numeric->Rs)
+    {
+#ifndef NRECIPROCAL
+       if (Numeric->do_recip)
+       {
+           PRINTF4 (("\nScale factors applied via multiplication\n")) ;
+       }
+       else
+#endif
+       {
+           PRINTF4 (("\nScale factors applied via division\n")) ;
+       }
+       PRINTF4 (("Scale factors, Rs: ")) ;
+       (void) UMF_report_vector (n_row, Numeric->Rs, (double *) NULL,
+           prl, FALSE, TRUE) ;
+    }
+    else
+    {
+       PRINTF4 (("Scale factors, Rs: (not present)\n")) ;
+    }
+
+    PRINTF4 (("\nP: row ")) ;
+    if (UMF_report_perm (n_row, Numeric->Rperm, W, prl, 0) != UMFPACK_OK)
+    {
+       (void) UMF_free ((void *) W) ;
+       return (UMFPACK_ERROR_invalid_Numeric_object) ;
+    }
+
+    PRINTF4 (("\nQ: column ")) ;
+    if (UMF_report_perm (n_col, Numeric->Cperm, W, prl, 0) != UMFPACK_OK)
+    {
+       (void) UMF_free ((void *) W) ;
+       return (UMFPACK_ERROR_invalid_Numeric_object) ;
+    }
+
+    if (!report_L (Numeric, W, prl))
+    {
+       (void) UMF_free ((void *) W) ;
+       PRINTF ((" ERROR: L factor invalid\n\n")) ;
+       return (UMFPACK_ERROR_invalid_Numeric_object) ;
+    }
+
+    if (!report_U (Numeric, W, prl))
+    {
+       (void) UMF_free ((void *) W) ;
+       PRINTF ((" ERROR: U factor invalid\n\n")) ;
+       return (UMFPACK_ERROR_invalid_Numeric_object) ;
+    }
+
+    /* The diagonal of U is in "merged" (Entry) form, not "split" form. */
+    PRINTF4 (("\ndiagonal of U: ")) ;
+    (void) UMF_report_vector (n_inner, (double *) Numeric->D, (double *) NULL,
+       prl, FALSE, FALSE) ;
+
+    (void) UMF_free ((void *) W) ;
+
+    PRINTF4 (("    Numeric object:  ")) ;
+    PRINTF (("OK\n\n")) ;
+    return (UMFPACK_OK) ;
+}
+
+
+/* ========================================================================== */
+/* === report_L ============================================================= */
+/* ========================================================================== */
+
+PRIVATE Int report_L
+(
+    NumericType *Numeric,
+    Int Pattern [ ],
+    Int prl
+)
+{
+    Int k, deg, *ip, j, row, n_row, *Lpos, *Lilen, valid, k1,
+       *Lip, newLchain, llen, prl1, pos, lp, p, npiv, n1, *Li ;
+    Entry *xp, *Lval ;
+
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (prl >= 3) ;
+
+    n_row = Numeric->n_row ;
+    npiv = Numeric->npiv ;
+    n1 = Numeric->n1 ;
+    Lpos = Numeric->Lpos ;
+    Lilen = Numeric->Lilen ;
+    Lip = Numeric->Lip ;
+    prl1 = prl ;
+    deg = 0 ;
+
+    PRINTF4 ((
+    "\nL in Numeric object, in column-oriented compressed-pattern form:\n"
+    "    Diagonal entries are all equal to 1.0 (not stored)\n")) ;
+
+    ASSERT (Pattern != (Int *) NULL) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* print L */
+    /* ---------------------------------------------------------------------- */
+
+    k1 = 12 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* print the singleton columns of L */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = 0 ; k < n1 ; k++)
+    {
+       if (k1 > 0)
+       {
+           prl = prl1 ;
+       }
+       lp = Lip [k] ;
+       deg = Lilen [k] ;
+       Li = (Int *) (Numeric->Memory + lp) ;
+       lp += UNITS (Int, deg) ;
+       Lval = (Entry *) (Numeric->Memory + lp) ;
+       if (k1-- > 0)
+       {
+           prl = prl1 ;
+       }
+       else if (prl == 4)
+       {
+           PRINTF (("    ...\n")) ;
+           prl-- ;
+       }
+       PRINTF4 (("\n    column "ID":", INDEX (k))) ;
+       PRINTF4 (("  length "ID".\n", deg)) ;
+       for (j = 0 ; j < deg ; j++)
+       {
+           row = Li [j] ;
+           PRINTF4 (("\trow "ID" : ", INDEX (row))) ;
+           if (prl >= 4) PRINT_ENTRY (Lval [j]) ;
+           if (row <= k || row >= n_row)
+           {
+               return (FALSE) ;
+           }
+           PRINTF4 (("\n")) ;
+           /* truncate printout, but continue to check L */
+           if (prl == 4 && j == 9 && deg > 10)
+           {
+               PRINTF (("\t...\n")) ;
+               prl-- ;
+           }
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* print the regular columns of L */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = n1 ; k < npiv ; k++)
+    {
+       /* if prl is 4, print the first 10 entries of the first 10 columns */
+       if (k1 > 0)
+       {
+           prl = prl1 ;
+       }
+
+       lp = Lip [k] ;
+       newLchain = (lp < 0) ;
+       if (newLchain)
+       {
+           lp = -lp ;
+           deg = 0 ;
+       }
+
+       if (k1-- > 0)
+       {
+           prl = prl1 ;
+       }
+       else if (prl == 4)
+       {
+           PRINTF (("    ...\n")) ;
+           prl-- ;
+       }
+
+       PRINTF4 (("\n    column "ID":", INDEX (k))) ;
+
+       /* ------------------------------------------------------------------ */
+       /* make column of L in Pattern [0..deg-1] */
+       /* ------------------------------------------------------------------ */
+
+       /* remove pivot row */
+       pos = Lpos [k] ;
+       if (pos != EMPTY)
+       {
+           PRINTF4 (("  remove row "ID" at position "ID".",
+               INDEX (Pattern [pos]), INDEX (pos))) ;
+           valid = (!newLchain) && (deg > 0) && (pos < deg) && (pos >= 0)
+               && (Pattern [pos] == k) ;
+           if (!valid)
+           {
+               return (FALSE) ;
+           }
+           Pattern [pos] = Pattern [--deg] ;
+       }
+
+       /* concatenate the pattern */
+       llen = Lilen [k] ;
+       if (llen < 0)
+       {
+           return (FALSE) ;
+       }
+       p = lp + UNITS (Int, llen) ;
+       xp = (Entry *) (Numeric->Memory + p) ;
+       if ((llen > 0 || deg > 0)
+           && (p + (Int) UNITS (Entry, deg) > Numeric->size))
+       {
+           return (FALSE) ;
+       }
+       if (llen > 0)
+       {
+           PRINTF4 (("  add "ID" entries.", llen)) ;
+           ip = (Int *) (Numeric->Memory + lp) ;
+           for (j = 0 ; j < llen ; j++)
+           {
+               Pattern [deg++] = *ip++ ;
+           }
+       }
+
+       /* ------------------------------------------------------------------ */
+       /* print column k of L */
+       /* ------------------------------------------------------------------ */
+
+       PRINTF4 (("  length "ID".", deg)) ;
+       if (newLchain)
+       {
+           PRINTF4 (("  Start of Lchain.")) ;
+       }
+       PRINTF4 (("\n")) ;
+
+       for (j = 0 ; j < deg ; j++)
+       {
+           row = Pattern [j] ;
+           PRINTF4 (("\trow "ID" : ", INDEX (row))) ;
+           if (prl >= 4) PRINT_ENTRY (*xp) ;
+           if (row <= k || row >= n_row)
+           {
+               return (FALSE) ;
+           }
+           PRINTF4 (("\n")) ;
+           xp++ ;
+           /* truncate printout, but continue to check L */
+           if (prl == 4 && j == 9 && deg > 10)
+           {
+               PRINTF (("\t...\n")) ;
+               prl-- ;
+           }
+       }
+    }
+
+    PRINTF4 (("\n")) ;
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === report_U ============================================================= */
+/* ========================================================================== */
+
+PRIVATE Int report_U
+(
+    NumericType *Numeric,
+    Int Pattern [ ],
+    Int prl
+)
+{
+    /* ---------------------------------------------------------------------- */
+
+    Int k, deg, j, *ip, col, *Upos, *Uilen, k1, prl1, pos,
+       *Uip, n_col, ulen, p, newUchain, up, npiv, n1, *Ui ;
+    Entry *xp, *Uval ;
+
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (prl >= 3) ;
+
+    n_col = Numeric->n_col ;
+    npiv = Numeric->npiv ;
+    n1 = Numeric->n1 ;
+    Upos = Numeric->Upos ;
+    Uilen = Numeric->Uilen ;
+    Uip = Numeric->Uip ;
+    prl1 = prl ;
+
+    PRINTF4 ((
+    "\nU in Numeric object, in row-oriented compressed-pattern form:\n"
+    "    Diagonal is stored separately.\n")) ;
+
+    ASSERT (Pattern != (Int *) NULL) ;
+
+    k1 = 12 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* print the sparse part of U */
+    /* ---------------------------------------------------------------------- */
+
+    deg = Numeric->ulen ;
+    if (deg > 0)
+    {
+       /* make last pivot row of U (singular matrices only) */
+       for (j = 0 ; j < deg ; j++)
+       {
+           Pattern [j] = Numeric->Upattern [j] ;
+       }
+    }
+
+    PRINTF4 (("\n    row "ID":  length "ID".  End of Uchain.\n", INDEX (npiv-1),
+       deg)) ;
+
+    for (k = npiv-1 ; k >= n1 ; k--)
+    {
+
+       /* ------------------------------------------------------------------ */
+       /* print row k of U */
+       /* ------------------------------------------------------------------ */
+
+       /* if prl is 3, print the first 10 entries of the first 10 columns */
+       if (k1 > 0)
+       {
+           prl = prl1 ;
+       }
+
+       up = Uip [k] ;
+       ulen = Uilen [k] ;
+       if (ulen < 0)
+       {
+           return (FALSE) ;
+       }
+       newUchain = (up < 0) ;
+       if (newUchain)
+       {
+           up = -up ;
+           p = up + UNITS (Int, ulen) ;
+       }
+       else
+       {
+           p = up ;
+       }
+       xp = (Entry *) (Numeric->Memory + p) ;
+       if (deg > 0 && (p + (Int) UNITS (Entry, deg) > Numeric->size))
+       {
+           return (FALSE) ;
+       }
+       for (j = 0 ; j < deg ; j++)
+       {
+           col = Pattern [j] ;
+           PRINTF4 (("\tcol "ID" :", INDEX (col))) ;
+           if (prl >= 4) PRINT_ENTRY (*xp) ;
+           if (col <= k || col >= n_col)
+           {
+               return (FALSE) ;
+           }
+           PRINTF4 (("\n")) ;
+           xp++ ;
+           /* truncate printout, but continue to check U */
+           if (prl == 4 && j == 9 && deg > 10)
+           {
+               PRINTF (("\t...\n")) ;
+               prl-- ;
+           }
+       }
+
+       /* ------------------------------------------------------------------ */
+       /* make row k-1 of U in Pattern [0..deg-1] */
+       /* ------------------------------------------------------------------ */
+
+       if (k1-- > 0)
+       {
+           prl = prl1 ;
+       }
+       else if (prl == 4)
+       {
+           PRINTF (("    ...\n")) ;
+           prl-- ;
+       }
+
+       if (k > 0)
+       {
+           PRINTF4 (("\n    row "ID":  ", INDEX (k-1))) ;
+       }
+
+       if (newUchain)
+       {
+           /* next row is a new Uchain */
+           if (k > 0)
+           {
+               deg = ulen ;
+               PRINTF4 (("length "ID".  End of Uchain.\n", deg)) ;
+               if (up + (Int) UNITS (Int, ulen) > Numeric->size)
+               {
+                   return (FALSE) ;
+               }
+               ip = (Int *) (Numeric->Memory + up) ;
+               for (j = 0 ; j < deg ; j++)
+               {
+                   Pattern [j] = *ip++ ;
+               }
+           }
+       }
+       else
+       {
+           if (ulen > 0)
+           {
+               PRINTF4 (("remove "ID" entries.  ", ulen)) ;
+           }
+           deg -= ulen ;
+           if (deg < 0)
+           {
+               return (FALSE) ;
+           }
+           pos = Upos [k] ;
+           if (pos != EMPTY)
+           {
+               /* add the pivot column */
+               PRINTF4 (("add column "ID" at position "ID".  ",
+                   INDEX (k), INDEX (pos))) ;
+               if (pos < 0 || pos > deg)
+               {
+                   return (FALSE) ;
+               }
+               Pattern [deg++] = Pattern [pos] ;
+               Pattern [pos] = k ;
+           }
+           PRINTF4 (("length "ID".\n", deg)) ;
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* print the singleton rows of U */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = n1 - 1 ; k >= 0 ; k--)
+    {
+       if (k1 > 0)
+       {
+           prl = prl1 ;
+       }
+       up = Uip [k] ;
+       deg = Uilen [k] ;
+       Ui = (Int *) (Numeric->Memory + up) ;
+       up += UNITS (Int, deg) ;
+       Uval = (Entry *) (Numeric->Memory + up) ;
+       if (k1-- > 0)
+       {
+           prl = prl1 ;
+       }
+       else if (prl == 4)
+       {
+           PRINTF (("    ...\n")) ;
+           prl-- ;
+       }
+       PRINTF4 (("\n    row "ID":", INDEX (k))) ;
+       PRINTF4 (("  length "ID".\n", deg)) ;
+       for (j = 0 ; j < deg ; j++)
+       {
+           col = Ui [j] ;
+           PRINTF4 (("\tcol "ID" : ", INDEX (col))) ;
+           if (prl >= 4) PRINT_ENTRY (Uval [j]) ;
+           if (col <= k || col >= n_col)
+           {
+               return (FALSE) ;
+           }
+           PRINTF4 (("\n")) ;
+           /* truncate printout, but continue to check U */
+           if (prl == 4 && j == 9 && deg > 10)
+           {
+               PRINTF (("\t...\n")) ;
+               prl-- ;
+           }
+       }
+    }
+
+    prl = prl1 ;
+    PRINTF4 (("\n")) ;
+    return (TRUE) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_perm.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_perm.c
new file mode 100644 (file)
index 0000000..2dc4c13
--- /dev/null
@@ -0,0 +1,45 @@
+/* ========================================================================== */
+/* === UMFPACK_report_perm ================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Prints a permutation vector.  See umfpack_report_perm.h
+    for details.
+
+    Dynamic memory usage:  Allocates a size max(np,1)*sizeof(Int) workspace via
+    a single call to UMF_malloc and then frees all of it via UMF_free on return.
+*/
+
+#include "umf_internal.h"
+#include "umf_report_perm.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+
+GLOBAL Int UMFPACK_report_perm
+(
+    Int np,
+    const Int Perm [ ],
+    const double Control [UMFPACK_CONTROL]
+)
+{
+    Int prl, *W, status ;
+
+    prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ;
+
+    if (prl <= 2)
+    {
+       return (UMFPACK_OK) ;
+    }
+
+    W = (Int *) UMF_malloc (MAX (np,1), sizeof (Int)) ;
+    status = UMF_report_perm (np, Perm, W, prl, 1) ;
+    (void) UMF_free ((void *) W) ;
+    return (status) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_status.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_status.c
new file mode 100644 (file)
index 0000000..06bc924
--- /dev/null
@@ -0,0 +1,119 @@
+/* ========================================================================== */
+/* === UMFPACK_report_status ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Prints the return value from other UMFPACK_* routines.
+    See umfpack_report_status.h for details.
+*/
+
+#include "umf_internal.h"
+
+GLOBAL void UMFPACK_report_status
+(
+    const double Control [UMFPACK_CONTROL],
+    Int status
+)
+{
+    Int prl ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get control settings and status to determine what to print */
+    /* ---------------------------------------------------------------------- */
+
+    prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ;
+
+    if (prl < 1)
+    {
+       /* no output generated if prl is less than 1 */
+       return ;
+    }
+
+    if (status == UMFPACK_OK && prl <= 1)
+    {
+       /* no output generated if prl is 1 or less and no error occured. */
+       /* note that the default printing level is 1. */
+       return ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* print umfpack license, copyright, version, and status condition */
+    /* ---------------------------------------------------------------------- */
+
+    PRINTF  (("\n")) ;
+    PRINTF4 (("%s\n", UMFPACK_COPYRIGHT)) ;
+    PRINTF6 (("%s", UMFPACK_LICENSE_PART1)) ;
+    PRINTF6 (("%s", UMFPACK_LICENSE_PART2)) ;
+    PRINTF6 (("%s", UMFPACK_LICENSE_PART3)) ;
+    PRINTF  (("%s: ", UMFPACK_VERSION)) ;
+
+    switch (status)
+    {
+       case UMFPACK_OK:
+           PRINTF (("OK\n")) ;
+           break ;
+
+       case UMFPACK_WARNING_singular_matrix:
+           PRINTF (("WARNING: matrix is singular\n")) ;
+           break ;
+
+       case UMFPACK_ERROR_out_of_memory:
+           PRINTF (("ERROR: out of memory\n")) ;
+           break ;
+
+       case UMFPACK_ERROR_invalid_Numeric_object:
+           PRINTF (("ERROR: Numeric object is invalid\n")) ;
+           break ;
+
+       case UMFPACK_ERROR_invalid_Symbolic_object:
+           PRINTF (("ERROR: Symbolic object is invalid\n")) ;
+           break ;
+
+       case UMFPACK_ERROR_argument_missing:
+           PRINTF (("ERROR: required argument(s) missing\n")) ;
+           break ;
+
+       case UMFPACK_ERROR_n_nonpositive:
+           PRINTF (("ERROR: dimension (n_row or n_col) must be > 0\n")) ;
+           break ;
+
+       case UMFPACK_ERROR_invalid_matrix:
+           PRINTF (("ERROR: input matrix is invalid\n")) ;
+           break ;
+
+       case UMFPACK_ERROR_invalid_system:
+           PRINTF (("ERROR: system argument invalid\n")) ;
+           break ;
+
+       case UMFPACK_ERROR_invalid_permutation:
+           PRINTF (("ERROR: invalid permutation\n")) ;
+           break ;
+
+       case UMFPACK_ERROR_different_pattern:
+           PRINTF (("ERROR: pattern of matrix (Ap and/or Ai) has changed\n")) ;
+           break ;
+
+       case UMFPACK_ERROR_internal_error:
+           PRINTF (("INTERNAL ERROR!\n"
+           "Input arguments might be corrupted or aliased, or an internal\n"
+           "error has occurred.  Check your input arguments with the\n"
+           "umfpack_*_report_* routines before calling the umfpack_*\n"
+           "computational routines.  Recompile UMFPACK with debugging\n"
+           "enabled, and look for failed assertions.  If all else fails\n"
+           "please report this error to Tim Davis (davis@cise.ufl.edu).\n"
+           )) ;
+           break ;
+
+       default:
+           PRINTF (("ERROR: Unrecognized error code: "ID"\n", status)) ;
+
+    }
+    PRINTF  (("\n")) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_symbolic.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_symbolic.c
new file mode 100644 (file)
index 0000000..14503d9
--- /dev/null
@@ -0,0 +1,229 @@
+/* ========================================================================== */
+/* === UMFPACK_report_symbolic ============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Prints the Symbolic object. See umfpack_report_symbolic.h
+    for details.  Does not print new Cdeg, Rdeg, Esize, and the Diagonal_map.
+
+    Dynamic memory usage:  Allocates a size MAX (n_row,n_col)*sizeof(Int)
+    workspace via a single call to UMF_malloc and then frees all of it via
+    UMF_free on return.  The workspace is not allocated if an early error
+    return occurs before the workspace is needed.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_symbolic.h"
+#include "umf_report_perm.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+
+GLOBAL Int UMFPACK_report_symbolic
+(
+    void *SymbolicHandle,
+    const double Control [UMFPACK_CONTROL]
+)
+{
+    Int n_row, n_col, nz, nchains, nfr, maxnrows, maxncols, prl,
+       k, chain, frontid, frontid1, frontid2, kk, *Chain_start, *W,
+       *Chain_maxrows, *Chain_maxcols, *Front_npivcol, *Front_1strow,
+       *Front_leftmostdesc, *Front_parent, done, status1, status2 ;
+    SymbolicType *Symbolic ;
+
+    prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ;
+
+    if (prl <= 2)
+    {
+       return (UMFPACK_OK) ;
+    }
+
+    PRINTF (("Symbolic object: ")) ;
+
+    Symbolic = (SymbolicType *) SymbolicHandle ;
+    if (!UMF_valid_symbolic (Symbolic))
+    {
+       PRINTF (("ERROR: invalid\n")) ;
+       return (UMFPACK_ERROR_invalid_Symbolic_object) ;
+    }
+
+    n_row = Symbolic->n_row ;
+    n_col = Symbolic->n_col ;
+
+    nz = Symbolic->nz ;
+
+    nchains = Symbolic->nchains ;
+    nfr = Symbolic->nfr ;
+    maxnrows = Symbolic->maxnrows ;
+    maxncols = Symbolic->maxncols ;
+
+    Chain_start = Symbolic->Chain_start ;
+    Chain_maxrows = Symbolic->Chain_maxrows ;
+    Chain_maxcols = Symbolic->Chain_maxcols ;
+    Front_npivcol = Symbolic->Front_npivcol ;
+    Front_1strow = Symbolic->Front_1strow ;
+    Front_leftmostdesc = Symbolic->Front_leftmostdesc ;
+    Front_parent = Symbolic->Front_parent ;
+
+    if (prl >= 4)
+    {
+
+       PRINTF (("\n    matrix to be factorized:\n")) ;
+       PRINTF (("\tn_row: "ID" n_col: "ID"\n", n_row, n_col)) ;
+       PRINTF (("\tnumber of entries: "ID"\n", nz)) ;
+       PRINTF (("    block size used for dense matrix kernels:   "ID"\n",
+       Symbolic->nb)) ;
+
+       PRINTF (("    strategy used:                              ")) ;
+       /* strategy cannot be auto */
+       if (Symbolic->strategy == UMFPACK_STRATEGY_SYMMETRIC)
+       {
+           PRINTF (("symmetric")) ;
+       }
+       else if (Symbolic->strategy == UMFPACK_STRATEGY_UNSYMMETRIC)
+       {
+           PRINTF (("unsymmetric")) ;
+       }
+       else if (Symbolic->strategy == UMFPACK_STRATEGY_2BY2)
+       {
+           PRINTF (("symmetric 2-by-2")) ;
+       }
+       PRINTF (("\n")) ;
+
+       PRINTF (("    ordering used:                              ")) ;
+       if (Symbolic->ordering == UMFPACK_ORDERING_COLAMD)
+       {
+           PRINTF (("colamd on A\n")) ;
+       }
+       else if (Symbolic->ordering == UMFPACK_ORDERING_AMD)
+       {
+           PRINTF (("amd on A+A'\n")) ;
+       }
+       else if (Symbolic->ordering == UMFPACK_ORDERING_GIVEN)
+       {
+           PRINTF (("provided by user")) ;
+       }
+       PRINTF (("\n")) ;
+
+       PRINTF (("    performn column etree postorder:            ")) ;
+       if (Symbolic->fixQ)
+       {
+           PRINTF (("no\n")) ;
+       }
+       else
+       {
+           PRINTF (("yes\n")) ;
+       }
+
+       PRINTF (("    prefer diagonal pivoting (attempt P=Q):     ")) ;
+       if (Symbolic->prefer_diagonal)
+       {
+           PRINTF (("yes\n")) ;
+       }
+       else
+       {
+           PRINTF (("no\n")) ;
+       }
+
+       PRINTF (("    variable-size part of Numeric object:\n")) ;
+       PRINTF (("\tminimum initial size (Units): %.20g  (MBytes): %.1f\n",
+           Symbolic->dnum_mem_init_usage,
+           MBYTES (Symbolic->dnum_mem_init_usage))) ;
+       PRINTF (("\testimated peak size (Units):  %.20g  (MBytes): %.1f\n",
+           Symbolic->num_mem_usage_est,
+           MBYTES (Symbolic->num_mem_usage_est))) ;
+       PRINTF (("\testimated final size (Units): %.20g  (MBytes): %.1f\n",
+           Symbolic->num_mem_size_est,
+           MBYTES (Symbolic->num_mem_size_est))) ;
+       PRINTF (("    symbolic factorization memory usage (Units):"
+           " %.20g  (MBytes): %.1f\n",
+           Symbolic->peak_sym_usage,
+           MBYTES (Symbolic->peak_sym_usage))) ;
+       PRINTF (("    frontal matrices / supercolumns:\n")) ;
+       PRINTF (("\tnumber of frontal chains: "ID"\n", nchains)) ;
+       PRINTF (("\tnumber of frontal matrices: "ID"\n", nfr)) ;
+       PRINTF (("\tlargest frontal matrix row dimension: "ID"\n", maxnrows)) ;
+       PRINTF (("\tlargest frontal matrix column dimension: "ID"\n",maxncols));
+    }
+
+    k = 0 ;
+    done = FALSE ;
+
+    for (chain = 0 ; chain < nchains ; chain++)
+    {
+       frontid1 = Chain_start [chain] ;
+       frontid2 = Chain_start [chain+1] - 1 ;
+       PRINTF4 (("\n    Frontal chain: "ID".  Frontal matrices "ID" to "ID"\n",
+           INDEX (chain), INDEX (frontid1), INDEX (frontid2))) ;
+       PRINTF4 (("\tLargest frontal matrix in Frontal chain: "ID"-by-"ID"\n",
+           Chain_maxrows [chain], Chain_maxcols [chain])) ;
+       for (frontid = frontid1 ; frontid <= frontid2 ; frontid++)
+       {
+           kk = Front_npivcol [frontid] ;
+           PRINTF4 (("\tFront: "ID"  pivot cols: "ID" (pivot columns "ID" to "
+               ID")\n", INDEX (frontid), kk, INDEX (k), INDEX (k+kk-1))) ;
+           PRINTF4 (("\t    pivot row candidates: "ID" to "ID"\n",
+               INDEX (Front_1strow [Front_leftmostdesc [frontid]]),
+               INDEX (Front_1strow [frontid+1]-1))) ;
+           PRINTF4 (("\t    leftmost descendant: "ID"\n",
+               INDEX (Front_leftmostdesc [frontid]))) ;
+           PRINTF4 (("\t    1st new candidate row : "ID"\n",
+               INDEX (Front_1strow [frontid]))) ;
+           PRINTF4 (("\t    parent:")) ;
+           if (Front_parent [frontid] == EMPTY)
+           {
+               PRINTF4 ((" (none)\n")) ;
+           }
+           else
+           {
+               PRINTF4 ((" "ID"\n", INDEX (Front_parent [frontid]))) ;
+           }
+           done = (frontid == 20 && frontid < nfr-1 && prl == 4) ;
+           if (done)
+           {
+               PRINTF4 (("\t...\n")) ;
+               break ;
+           }
+           k += kk ;
+       }
+       if (Front_npivcol [nfr] != 0)
+       {
+           PRINTF4 (("\tFront: "ID" placeholder for "ID" empty columns\n",
+               INDEX (nfr), Front_npivcol [nfr])) ;
+       }
+       if (done)
+       {
+           break ;
+       }
+    }
+
+    W = (Int *) UMF_malloc (MAX (n_row, n_col), sizeof (Int)) ;
+    if (!W)
+    {
+       PRINTF (("ERROR: out of memory to check Symbolic object\n\n")) ;
+       return (UMFPACK_ERROR_out_of_memory) ;
+    }
+
+    PRINTF4 (("\nInitial column permutation, Q1: ")) ;
+    status1 = UMF_report_perm (n_col, Symbolic->Cperm_init, W, prl, 0) ;
+
+    PRINTF4 (("\nInitial row permutation, P1: ")) ;
+    status2 = UMF_report_perm (n_row, Symbolic->Rperm_init, W, prl, 0) ;
+
+    (void) UMF_free ((void *) W) ;
+
+    if (status1 != UMFPACK_OK || status2 != UMFPACK_OK)
+    {
+       return (UMFPACK_ERROR_invalid_Symbolic_object) ;
+    }
+
+    PRINTF4 (("    Symbolic object:  ")) ;
+    PRINTF (("OK\n\n")) ;
+    return (UMFPACK_OK) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_triplet.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_triplet.c
new file mode 100644 (file)
index 0000000..d044dad
--- /dev/null
@@ -0,0 +1,101 @@
+/* ========================================================================== */
+/* === UMFPACK_report_triplet =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Prints a matrix in triplet form.  See
+    umfpack_report_triplet.h for details.
+*/
+
+#include "umf_internal.h"
+
+GLOBAL Int UMFPACK_report_triplet
+(
+    Int n_row,
+    Int n_col,
+    Int nz,
+    const Int Ti [ ],
+    const Int Tj [ ],
+    const double Tx [ ],
+#ifdef COMPLEX
+    const double Tz [ ],
+#endif
+    const double Control [UMFPACK_CONTROL]
+)
+{
+    Int prl, prl1, k, i, j, do_values ;
+    Entry t ;
+
+    prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ;
+
+    if (prl <= 2)
+    {
+       return (UMFPACK_OK) ;
+    }
+
+    PRINTF (("triplet-form matrix, n_row = "ID", n_col = "ID" nz = "ID". ",
+       n_row, n_col, nz)) ;
+
+    if (!Ti || !Tj)
+    {
+       PRINTF (("ERROR: indices not present\n\n")) ;
+       return (UMFPACK_ERROR_argument_missing) ;
+    }
+
+    if (n_row <= 0 || n_col <= 0)
+    {
+       PRINTF (("ERROR: n_row or n_col is <= 0\n\n")) ;
+       return (UMFPACK_ERROR_n_nonpositive) ;
+    }
+
+    if (nz < 0)
+    {
+       PRINTF (("ERROR: nz is < 0\n\n")) ;
+       return (UMFPACK_ERROR_invalid_matrix) ;
+    }
+
+    PRINTF4 (("\n")) ;
+
+#ifdef COMPLEX
+    do_values = Tx && Tz ;
+#else
+    do_values = Tx != (double *) NULL ;
+#endif
+
+    prl1 = prl ;
+    for (k = 0 ; k < nz ; k++)
+    {
+       i = Ti [k] ;
+       j = Tj [k] ;
+       PRINTF4 (("    "ID" : "ID" "ID" ", INDEX (k), INDEX (i), INDEX (j))) ;
+       if (do_values && prl >= 4)
+       {
+           ASSIGN (t, Tx [k], Tz [k]) ;
+           PRINT_ENTRY (t) ;
+       }
+       PRINTF4 (("\n")) ;
+       if (i < 0 || i >= n_row || j < 0 || j >= n_col)
+       {
+           /* invalid triplet */
+           PRINTF (("ERROR: invalid triplet\n\n")) ;
+           return (UMFPACK_ERROR_invalid_matrix) ;
+       }
+       if (prl == 4 && k == 9 && nz > 10)
+       {
+           PRINTF (("    ...\n")) ;
+           prl-- ;
+       }
+    }
+    prl = prl1 ;
+
+    PRINTF4 (("    triplet-form matrix ")) ;
+    PRINTF (("OK\n\n")) ;
+    return (UMFPACK_OK) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_vector.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_vector.c
new file mode 100644 (file)
index 0000000..d5e18a1
--- /dev/null
@@ -0,0 +1,44 @@
+/* ========================================================================== */
+/* === UMFPACK_report_vector ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Prints a real or complex vector.
+    See umfpack_report_vector.h for details.
+*/
+
+#include "umf_internal.h"
+#include "umf_report_vector.h"
+
+GLOBAL Int UMFPACK_report_vector
+(
+    Int n,
+    const double Xx [ ],
+#ifdef COMPLEX
+    const double Xz [ ],
+#endif
+    const double Control [UMFPACK_CONTROL]
+)
+{
+    Int prl ;
+
+#ifndef COMPLEX
+    double *Xz = (double *) NULL ;
+#endif
+
+    prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ;
+
+    if (prl <= 2)
+    {
+       return (UMFPACK_OK) ;
+    }
+
+    return (UMF_report_vector (n, Xx, Xz, prl, TRUE, FALSE)) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_save_numeric.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_save_numeric.c
new file mode 100644 (file)
index 0000000..b7803b7
--- /dev/null
@@ -0,0 +1,93 @@
+/* ========================================================================== */
+/* === UMFPACK_save_numeric ================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Saves a Numeric object to a file.  It can later be read back
+    in via a call to umfpack_*_load_numeric.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_numeric.h"
+
+#define WRITE(object,type,n) \
+{ \
+    ASSERT (object != (type *) NULL) ; \
+    if (fwrite (object, sizeof (type), n, f) != n) \
+    { \
+       fclose (f) ; \
+       return (UMFPACK_ERROR_file_IO) ; \
+    } \
+}
+
+/* ========================================================================== */
+/* === UMFPACK_save_numeric ================================================= */
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_save_numeric
+(
+    void *NumericHandle,
+    char *user_filename
+)
+{
+    NumericType *Numeric ;
+    char *filename ;
+    FILE *f ;
+
+    /* get the Numeric object */
+    Numeric = (NumericType *) NumericHandle ;
+
+    /* make sure the Numeric object is valid */
+    if (!UMF_valid_numeric (Numeric))
+    {
+       return (UMFPACK_ERROR_invalid_Numeric_object) ;
+    }
+
+    /* get the filename, or use the default name if filename is NULL */
+    if (user_filename == (char *) NULL)
+    {
+       filename = "numeric.umf" ;
+    }
+    else
+    {
+       filename = user_filename ;
+    }
+    f = fopen (filename, "wb") ;
+    if (!f)
+    {
+       return (UMFPACK_ERROR_file_IO) ;
+    }
+
+    /* write the Numeric object to the file, in binary */
+    WRITE (Numeric,        NumericType, 1) ;
+    WRITE (Numeric->D,     Entry, MIN (Numeric->n_row, Numeric->n_col)+1) ;
+    WRITE (Numeric->Rperm, Int,   Numeric->n_row+1) ;
+    WRITE (Numeric->Cperm, Int,   Numeric->n_col+1) ;
+    WRITE (Numeric->Lpos,  Int,   Numeric->npiv+1) ;
+    WRITE (Numeric->Lilen, Int,   Numeric->npiv+1) ;
+    WRITE (Numeric->Lip,   Int,   Numeric->npiv+1) ;
+    WRITE (Numeric->Upos,  Int,   Numeric->npiv+1) ;
+    WRITE (Numeric->Uilen, Int,   Numeric->npiv+1) ;
+    WRITE (Numeric->Uip,   Int,   Numeric->npiv+1) ;
+    if (Numeric->scale != UMFPACK_SCALE_NONE)
+    {
+       WRITE (Numeric->Rs, double, Numeric->n_row) ;
+    }
+    if (Numeric->ulen > 0)
+    {
+       WRITE (Numeric->Upattern, Int, Numeric->ulen+1) ;
+    }
+    WRITE (Numeric->Memory, Unit, Numeric->size) ;
+
+    /* close the file */
+    fclose (f) ;
+
+    return (UMFPACK_OK) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_save_symbolic.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_save_symbolic.c
new file mode 100644 (file)
index 0000000..7908b83
--- /dev/null
@@ -0,0 +1,96 @@
+/* ========================================================================== */
+/* === UMFPACK_save_symbolic ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Saves a Symbolic object to a file.  It can later be read
+    back in via a call to umfpack_*_load_symbolic.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_symbolic.h"
+
+#define WRITE(object,type,n) \
+{ \
+    ASSERT (object != (type *) NULL) ; \
+    if (fwrite (object, sizeof (type), n, f) != n) \
+    { \
+       fclose (f) ; \
+       return (UMFPACK_ERROR_file_IO) ; \
+    } \
+}
+
+/* ========================================================================== */
+/* === UMFPACK_save_symbolic ================================================ */
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_save_symbolic
+(
+    void *SymbolicHandle,
+    char *user_filename
+)
+{
+    SymbolicType *Symbolic ;
+    char *filename ;
+    FILE *f ;
+
+    /* get the Symbolic object */
+    Symbolic = (SymbolicType *) SymbolicHandle ;
+
+    /* make sure the Symbolic object is valid */
+    if (!UMF_valid_symbolic (Symbolic))
+    {
+       return (UMFPACK_ERROR_invalid_Symbolic_object) ;
+    }
+
+    /* get the filename, or use the default name if filename is NULL */
+    if (user_filename == (char *) NULL)
+    {
+       filename = "symbolic.umf" ;
+    }
+    else
+    {
+       filename = user_filename ;
+    }
+    f = fopen (filename, "wb") ;
+    if (!f)
+    {
+       return (UMFPACK_ERROR_file_IO) ;
+    }
+
+    /* write the Symbolic object to the file, in binary */
+    WRITE (Symbolic,                     SymbolicType, 1) ;
+    WRITE (Symbolic->Cperm_init,         Int, Symbolic->n_col+1) ;
+    WRITE (Symbolic->Rperm_init,         Int, Symbolic->n_row+1) ;
+    WRITE (Symbolic->Front_npivcol,      Int, Symbolic->nfr+1) ;
+    WRITE (Symbolic->Front_parent,       Int, Symbolic->nfr+1) ;
+    WRITE (Symbolic->Front_1strow,       Int, Symbolic->nfr+1) ;
+    WRITE (Symbolic->Front_leftmostdesc, Int, Symbolic->nfr+1) ;
+    WRITE (Symbolic->Chain_start,        Int, Symbolic->nchains+1) ;
+    WRITE (Symbolic->Chain_maxrows,      Int, Symbolic->nchains+1) ;
+    WRITE (Symbolic->Chain_maxcols,      Int, Symbolic->nchains+1) ;
+    WRITE (Symbolic->Cdeg,               Int, Symbolic->n_col+1) ;
+    WRITE (Symbolic->Rdeg,               Int, Symbolic->n_row+1) ;
+    if (Symbolic->esize > 0)
+    {
+       /* only when dense rows are present */
+       WRITE (Symbolic->Esize, Int, Symbolic->esize) ;
+    }
+    if (Symbolic->prefer_diagonal)
+    {
+       /* only when diagonal pivoting is prefered */
+       WRITE (Symbolic->Diagonal_map, Int, Symbolic->n_col+1) ;
+    }
+
+    /* close the file */
+    fclose (f) ;
+
+    return (UMFPACK_OK) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_scale.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_scale.c
new file mode 100644 (file)
index 0000000..90d0221
--- /dev/null
@@ -0,0 +1,112 @@
+/* ========================================================================== */
+/* === UMFPACK_scale ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Applies the scale factors computed during numerical
+    factorization to a vector. See umfpack_scale.h for more details.
+
+    The LU factorization is L*U = P*R*A*Q, where P and Q are permutation
+    matrices, and R is diagonal.  This routine computes X = R * B using the
+    matrix R stored in the Numeric object.
+
+    Returns FALSE if any argument is invalid, TRUE otherwise.
+
+    If R not present in the Numeric object, then R = I and no floating-point
+    work is done.  B is simply copied into X.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_numeric.h"
+
+GLOBAL Int UMFPACK_scale
+(
+    double Xx [ ],
+#ifdef COMPLEX
+    double Xz [ ],
+#endif
+    const double Bx [ ],
+#ifdef COMPLEX
+    const double Bz [ ],
+#endif
+    void *NumericHandle
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    NumericType *Numeric ;
+    Int n, i ;
+    double *Rs ;
+
+    Numeric = (NumericType *) NumericHandle ;
+    if (!UMF_valid_numeric (Numeric))
+    {
+       return (UMFPACK_ERROR_invalid_Numeric_object) ;
+    }
+
+    n = Numeric->n_row ;
+    Rs = Numeric->Rs ;
+
+    if (!Xx || !Bx
+#ifdef COMPLEX
+       || !Xz || !Bz
+#endif
+    )
+    {
+       return (UMFPACK_ERROR_argument_missing) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* X = R*B or R\B */
+    /* ---------------------------------------------------------------------- */
+
+    if (Rs != (double *) NULL)
+    {
+#ifndef NRECIPROCAL
+       if (Numeric->do_recip)
+       {
+           /* multiply by the scale factors */
+           for (i = 0 ; i < n ; i++)
+           {
+               Xx [i] = Bx [i] * Rs [i] ;
+#ifdef COMPLEX
+               Xz [i] = Bz [i] * Rs [i] ;
+#endif
+           }
+       }
+       else
+#endif
+       {
+           /* divide by the scale factors */
+           for (i = 0 ; i < n ; i++)
+           {
+               Xx [i] = Bx [i] / Rs [i] ;
+#ifdef COMPLEX
+               Xz [i] = Bz [i] / Rs [i] ;
+#endif
+           }
+       }
+    }
+    else
+    {
+       /* no scale factors, just copy B into X */
+       for (i = 0 ; i < n ; i++)
+       {
+           Xx [i] = Bx [i] ;
+#ifdef COMPLEX
+           Xz [i] = Bz [i] ;
+#endif
+       }
+    }
+
+    return (UMFPACK_OK) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_solve.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_solve.c
new file mode 100644 (file)
index 0000000..30bf812
--- /dev/null
@@ -0,0 +1,249 @@
+/* ========================================================================== */
+/* === UMFPACK_solve ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Solves a linear system using the numerical factorization
+    computed by UMFPACK_numeric.  See umfpack_solve.h for more details.
+
+    For umfpack_*_solve:
+       Dynamic memory usage:  UMFPACK_solve calls UMF_malloc twice, for
+       workspace of size c*n*sizeof(double) + n*sizeof(Int), where c is
+       defined below.  On return, all of this workspace is free'd via UMF_free.
+
+    For umfpack_*_wsolve:
+       No dynamic memory usage.  Input arrays are used for workspace instead.
+       Pattern is a workspace of size n Integers.  The double array W must be
+       at least of size c*n, where c is defined below.
+
+    If iterative refinement is requested, and Ax=b, A'x=b or A.'x=b is being
+    solved, and the matrix A is not singular, then c is 5 for the real version
+    and 10 for the complex version.  Otherwise, c is 1 for the real version and
+    4 for the complex version.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_numeric.h"
+#include "umf_solve.h"
+
+#ifndef WSOLVE
+#include "umf_malloc.h"
+#include "umf_free.h"
+#ifndef NDEBUG
+PRIVATE Int init_count ;
+#endif
+#endif
+
+GLOBAL Int
+#ifdef WSOLVE
+UMFPACK_wsolve
+#else
+UMFPACK_solve
+#endif
+(
+    Int sys,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const double Ax [ ],
+#ifdef COMPLEX
+    const double Az [ ],
+#endif
+    double Xx [ ],
+#ifdef COMPLEX
+    double Xz [ ],
+#endif
+    const double Bx [ ],
+#ifdef COMPLEX
+    const double Bz [ ],
+#endif
+    void *NumericHandle,
+    const double Control [UMFPACK_CONTROL],
+    double User_Info [UMFPACK_INFO]
+#ifdef WSOLVE
+    , Int Pattern [ ],
+    double W [ ]
+#endif
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    NumericType *Numeric ;
+    Int n, i, irstep, status ;
+    double Info2 [UMFPACK_INFO], *Info, /* tstart, tend */ stats [2] ;
+#ifndef WSOLVE
+    Int *Pattern, wsize ;
+    double *W ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* get the amount of time used by the process so far */
+    /* ---------------------------------------------------------------------- */
+
+    umfpack_tic (stats) ;
+
+#ifndef WSOLVE
+#ifndef NDEBUG
+    init_count = UMF_malloc_count ;
+#endif
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* get parameters */
+    /* ---------------------------------------------------------------------- */
+
+    irstep = GET_CONTROL (UMFPACK_IRSTEP, UMFPACK_DEFAULT_IRSTEP) ;
+
+    if (User_Info != (double *) NULL)
+    {
+       /* return Info in user's array */
+       Info = User_Info ;
+       /* clear the parts of Info that are set by UMFPACK_solve */
+       for (i = UMFPACK_IR_TAKEN ; i <= UMFPACK_SOLVE_TIME ; i++)
+       {
+           Info [i] = EMPTY ;
+       }
+    }
+    else
+    {
+       /* no Info array passed - use local one instead */
+       Info = Info2 ;
+       for (i = 0 ; i < UMFPACK_INFO ; i++)
+       {
+           Info [i] = EMPTY ;
+       }
+    }
+
+    Info [UMFPACK_STATUS] = UMFPACK_OK ;
+    Info [UMFPACK_SOLVE_FLOPS] = 0 ;
+
+    Numeric = (NumericType *) NumericHandle ;
+    if (!UMF_valid_numeric (Numeric))
+    {
+       Info [UMFPACK_STATUS] = UMFPACK_ERROR_invalid_Numeric_object ;
+       return (UMFPACK_ERROR_invalid_Numeric_object) ;
+    }
+
+    Info [UMFPACK_NROW] = Numeric->n_row ;
+    Info [UMFPACK_NCOL] = Numeric->n_col ;
+
+    if (Numeric->n_row != Numeric->n_col)
+    {
+       /* only square systems can be handled */
+       Info [UMFPACK_STATUS] = UMFPACK_ERROR_invalid_system ;
+       return (UMFPACK_ERROR_invalid_system) ;
+    }
+    n = Numeric->n_row ;
+    if (Numeric->nnzpiv < n
+       || SCALAR_IS_ZERO (Numeric->rcond) || SCALAR_IS_NAN (Numeric->rcond))
+    {
+       /* turn off iterative refinement if A is singular */
+       /* or if U has NaN's on the diagonal. */
+       irstep = 0 ;
+    }
+
+    if (!Xx || !Bx
+#ifdef COMPLEX
+       || !Xz || !Bz
+#endif
+    )
+    {
+       Info [UMFPACK_STATUS] = UMFPACK_ERROR_argument_missing ;
+       return (UMFPACK_ERROR_argument_missing) ;
+    }
+
+    if (sys >= UMFPACK_Pt_L)
+    {
+       /* no iterative refinement except for nonsingular Ax=b, A'x=b, A.'x=b */
+       irstep = 0 ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate or check the workspace */
+    /* ---------------------------------------------------------------------- */
+
+#ifdef WSOLVE
+
+    if (!W || !Pattern)
+    {
+       Info [UMFPACK_STATUS] = UMFPACK_ERROR_argument_missing ;
+       return (UMFPACK_ERROR_argument_missing) ;
+    }
+
+#else
+
+#ifdef COMPLEX
+    if (irstep > 0)
+    {
+       wsize = 10*n ;          /* W, X, Z, S, Y, B2 */
+    }
+    else
+    {
+       wsize = 4*n ;           /* W, X */
+    }
+#else
+    if (irstep > 0)
+    {
+       wsize = 5*n ;           /* W, Z, S, Y, B2 */
+    }
+    else
+    {
+       wsize = n ;             /* W */
+    }
+#endif
+
+    Pattern = (Int *) UMF_malloc (n, sizeof (Int)) ;
+    W = (double *) UMF_malloc (wsize, sizeof (double)) ;
+    if (!W || !Pattern)
+    {
+       DEBUGm4 (("out of memory: solve work\n")) ;
+       Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+       (void) UMF_free ((void *) W) ;
+       (void) UMF_free ((void *) Pattern) ;
+       return (UMFPACK_ERROR_out_of_memory) ;
+    }
+
+#endif /* WSOLVE */
+
+    /* ---------------------------------------------------------------------- */
+    /* solve the system */
+    /* ---------------------------------------------------------------------- */
+
+    status = UMF_solve (sys, Ap, Ai, Ax, Xx, Bx,
+#ifdef COMPLEX
+       Az, Xz, Bz,
+#endif
+       Numeric, irstep, Info, Pattern, W) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* free the workspace (if allocated) */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef WSOLVE
+    (void) UMF_free ((void *) W) ;
+    (void) UMF_free ((void *) Pattern) ;
+    ASSERT (UMF_malloc_count == init_count) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* get the time used by UMFPACK_*solve */
+    /* ---------------------------------------------------------------------- */
+
+    Info [UMFPACK_STATUS] = status ;
+    if (status >= 0)
+    {
+       umfpack_toc (stats) ;
+       Info [UMFPACK_SOLVE_WALLTIME] = stats [0] ;
+       Info [UMFPACK_SOLVE_TIME] = stats [1] ;
+    }
+
+    return (status) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_symbolic.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_symbolic.c
new file mode 100644 (file)
index 0000000..2125695
--- /dev/null
@@ -0,0 +1,40 @@
+/* ========================================================================== */
+/* === UMFPACK_symbolic ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Performs a symbolic factorization.
+    See umfpack_symbolic.h for details.
+*/
+
+#include "umf_internal.h"
+
+GLOBAL Int UMFPACK_symbolic
+(
+    Int n_row,
+    Int n_col,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const double Ax [ ],
+#ifdef COMPLEX
+    const double Az [ ],
+#endif
+    void **SymbolicHandle,
+    const double Control [UMFPACK_CONTROL],
+    double Info [UMFPACK_INFO]
+)
+{
+    Int *Qinit = (Int *) NULL ;
+    return (UMFPACK_qsymbolic (n_row, n_col, Ap, Ai, Ax,
+#ifdef COMPLEX
+       Az,
+#endif
+       Qinit, SymbolicHandle, Control, Info)) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_tictoc.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_tictoc.c
new file mode 100644 (file)
index 0000000..706f3ac
--- /dev/null
@@ -0,0 +1,107 @@
+/* ========================================================================== */
+/* === umfpack_tictoc ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Returns the time in seconds used by the process, and
+    the current wall clock time.  BE CAREFUL:  if you compare the run time of
+    UMFPACK with other sparse matrix packages, be sure to use the same timer.
+    See umfpack_tictoc.h for details.
+
+    These routines conform to the POSIX standard.  See umf_config.h for
+    more details.
+*/
+
+#include "umf_internal.h"
+
+#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 */
+
+    struct tms t ;
+    double ticks ;
+
+    ticks = (double) sysconf (_SC_CLK_TCK) ;
+    stats [0] = (double) times (&t) / ticks ;
+    stats [1] = (double) (t.tms_utime + t.tms_stime) / ticks ;
+
+    /* if time is tiny, just return zero */
+    if (stats [0] < TINY_TIME) stats [0] = 0 ;
+    if (stats [1] < TINY_TIME) stats [1] = 0 ;
+}
+
+#else
+
+/* Generic ANSI C: use the ANSI clock function.  No wallclock time. */
+
+#include <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/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_timer.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_timer.c
new file mode 100644 (file)
index 0000000..be0e7fc
--- /dev/null
@@ -0,0 +1,85 @@
+/* ========================================================================== */
+/* === umfpack_timer ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Returns the time in seconds used by the process.  BE
+    CAREFUL:  if you compare the run time of UMFPACK with other sparse matrix
+    packages, be sure to use the same timer.  See umfpack_timer.h for details.
+    This was the timer used internally by UMFPACK Version 4.0.  See
+    umfpack_tictoc.h, which is the timer now used internally by UMFPACK V4.1.
+*/
+
+#ifdef 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/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_transpose.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_transpose.c
new file mode 100644 (file)
index 0000000..7dedecb
--- /dev/null
@@ -0,0 +1,109 @@
+/* ========================================================================== */
+/* === UMFPACK_transpose ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User callable.  Computes a permuted transpose, R = (A (P,Q))' in MATLAB
+    notation.  See umfpack_transpose.h for details.  A and R can be rectangular.
+    The matrix A may be singular.
+    The complex version can do transpose (') or array transpose (.').
+
+    Dynamic memory usage: A single call to UMF_malloc is made, for a workspace
+    of size max (n_row,n_col,1) * sizeof(Int).  This is then free'd on return,
+    via UMF_free.
+*/
+
+#include "umf_internal.h"
+#include "umf_transpose.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+
+#ifndef NDEBUG
+PRIVATE Int init_count ;
+#endif
+
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_transpose
+(
+    Int n_row,
+    Int n_col,
+    const Int Ap [ ],  /* size n_col+1 */
+    const Int Ai [ ],  /* size nz = Ap [n_col] */
+    const double Ax [ ], /* size nz, if present */
+#ifdef COMPLEX
+    const double Az [ ], /* size nz, if present */
+#endif
+
+    const Int P [ ],   /* P [k] = i means original row i is kth row in A(P,Q)*/
+                       /* P is identity if not present */
+                       /* size n_row, if present */
+
+    const Int Q [ ],   /* Q [k] = j means original col j is kth col in A(P,Q)*/
+                       /* Q is identity if not present */
+                       /* size n_col, if present */
+
+    Int Rp [ ],                /* size n_row+1 */
+    Int Ri [ ],                /* size nz */
+    double Rx [ ]      /* size nz, if present */
+#ifdef COMPLEX
+    , double Rz [ ]    /* size nz, if present */
+    , Int do_conjugate /* if true, then to conjugate transpose */
+                       /* otherwise, do array transpose */
+#endif
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int status, *W, nn ;
+
+#ifndef NDEBUG
+    init_count = UMF_malloc_count ;
+    UMF_dump_start ( ) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    nn = MAX (n_row, n_col) ;
+    nn = MAX (nn, 1) ;
+    W = (Int *) UMF_malloc (nn, sizeof (Int)) ;
+    if (!W)
+    {
+       DEBUGm4 (("out of memory: transpose work\n")) ;
+       ASSERT (UMF_malloc_count == init_count) ;
+       return (UMFPACK_ERROR_out_of_memory) ;
+    }
+    ASSERT (UMF_malloc_count == init_count + 1) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* C = (A (P,Q))' or (A (P,Q)).' */
+    /* ---------------------------------------------------------------------- */
+
+    status = UMF_transpose (n_row, n_col, Ap, Ai, Ax, P, Q, n_col, Rp, Ri, Rx,
+       W, TRUE
+#ifdef COMPLEX
+       , Az, Rz, do_conjugate
+#endif
+       ) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* free the workspace */
+    /* ---------------------------------------------------------------------- */
+
+    (void) UMF_free ((void *) W) ;
+    ASSERT (UMF_malloc_count == init_count) ;
+
+    return (status) ;
+}
diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_triplet_to_col.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_triplet_to_col.c
new file mode 100644 (file)
index 0000000..a868231
--- /dev/null
@@ -0,0 +1,229 @@
+/* ========================================================================== */
+/* === UMFPACK_triplet_to_col =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.      */
+/* Davis.  All Rights Reserved.  See ../README for License.                   */
+/* email: davis@cise.ufl.edu    CISE Department, Univ. of Florida.            */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User callable.  Converts triplet input to column-oriented form.  Duplicate
+    entries may exist (they are summed in the output).  The columns of the
+    column-oriented form are in sorted order.  The input is not modified.
+    Returns 1 if OK, 0 if an error occured.  See umfpack_triplet_to_col.h for
+    details.
+
+    If Map is present (a non-NULL pointer to an Int array of size nz), then on
+    output it holds the position of the triplets in the column-form matrix.
+    That is, suppose p = Map [k], and the k-th triplet is i=Ti[k], j=Tj[k], and
+    aij=Tx[k].  Then i=Ai[p], and aij will have been summed into Ax[p].  Also,
+    Ap[j] <= p < Ap[j+1].  The Map array is not computed if it is (Int *) NULL.
+
+    Dynamic memory usage:
+
+       If numerical values are present, then one (two for complex version)
+       workspace of size (nz+1)*sizeof(double) is allocated via UMF_malloc.
+       Next, 4 calls to UMF_malloc are made to obtain workspace of size
+       ((nz+1) + (n_row+1) + n_row + MAX (n_row,n_col)) * sizeof(Int).  All of
+       this workspace (4 to 6 objects) are free'd via UMF_free on return.
+
+       For the complex version, additional space is allocated.
+
+       An extra array of size nz*sizeof(Int) is allocated if Map is present.
+*/
+
+#include "umf_internal.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+#include "umf_triplet.h"
+
+#ifndef NDEBUG
+PRIVATE Int init_count ;
+#endif
+
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_triplet_to_col
+(
+    Int n_row,
+    Int n_col,
+    Int nz,
+    const Int Ti [ ],          /* size nz */
+    const Int Tj [ ],          /* size nz */
+    const double Tx [ ],       /* size nz */
+#ifdef COMPLEX
+    const double Tz [ ],       /* size nz */
+#endif
+    Int Ap [ ],                        /* size n_col + 1 */
+    Int Ai [ ],                        /* size nz */
+    double Ax [ ]              /* size nz */
+#ifdef COMPLEX
+    , double Az [ ]            /* size nz */
+#endif
+    , Int Map [ ]              /* size nz */
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    Int *RowCount, *Rp, *Rj, *W, nn, do_values, do_map, *Map2, status ;
+    double *Rx, *Rz ;
+
+#ifndef NDEBUG
+    UMF_dump_start ( ) ;
+    init_count = UMF_malloc_count ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    if (!Ai || !Ap || !Ti || !Tj)
+    {
+       return (UMFPACK_ERROR_argument_missing) ;
+    }
+
+    if (n_row <= 0 || n_col <= 0)              /* must be > 0 */
+    {
+       return (UMFPACK_ERROR_n_nonpositive) ;
+    }
+
+    if (nz < 0)                /* nz must be >= 0 (singular matrices are OK) */
+    {
+       return (UMFPACK_ERROR_invalid_matrix) ;
+    }
+
+    nn = MAX (n_row, n_col) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    Rx = (double *) NULL ;
+    Rz = (double *) NULL ;
+
+#ifdef COMPLEX
+    do_values = Ax && Tx && Az && Tz ;
+    if (do_values)
+    {
+       Rx = (double *) UMF_malloc (nz+1, sizeof (double)) ;
+       Rz = (double *) UMF_malloc (nz+1, sizeof (double)) ;
+       if (!Rx || !Rz)
+       {
+           DEBUGm4 (("out of memory: triplet work (complex)\n")) ;
+           (void) UMF_free ((void *) Rx) ;
+           (void) UMF_free ((void *) Rz) ;
+           ASSERT (UMF_malloc_count == init_count) ;
+           return (UMFPACK_ERROR_out_of_memory) ;
+       }
+    }
+#else
+    do_values = Ax && Tx ;
+    if (do_values)
+    {
+       Rx = (double *) UMF_malloc (nz+1, sizeof (double)) ;
+       if (!Rx)
+       {
+           DEBUGm4 (("out of memory: triplet work (real)\n")) ;
+           ASSERT (UMF_malloc_count == init_count) ;
+           return (UMFPACK_ERROR_out_of_memory) ;
+       }
+    }
+#endif
+
+    do_map = (Map != (Int *) NULL) ;
+    Map2 = (Int *) NULL ;
+    if (do_map)
+    {
+       DEBUG0 (("Do map:\n")) ;
+       Map2 = (Int *) UMF_malloc (nz+1, sizeof (Int)) ;
+       if (!Map2)
+       {
+           DEBUGm4 (("out of memory: triplet map\n")) ;
+           (void) UMF_free ((void *) Rx) ;
+           (void) UMF_free ((void *) Rz) ;
+           ASSERT (UMF_malloc_count == init_count) ;
+           return (UMFPACK_ERROR_out_of_memory) ;
+       }
+    }
+
+    Rj = (Int *) UMF_malloc (nz+1, sizeof (Int)) ;
+    Rp = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ;
+    RowCount = (Int *) UMF_malloc (n_row, sizeof (Int)) ;
+    W = (Int *) UMF_malloc (nn, sizeof (Int)) ;
+    if (!Rj || !Rp || !RowCount || !W)
+    {
+       DEBUGm4 (("out of memory: triplet work (int)\n")) ;
+       (void) UMF_free ((void *) Rx) ;
+       (void) UMF_free ((void *) Rz) ;
+       (void) UMF_free ((void *) Map2) ;
+       (void) UMF_free ((void *) Rp) ;
+       (void) UMF_free ((void *) Rj) ;
+       (void) UMF_free ((void *) RowCount) ;
+       (void) UMF_free ((void *) W) ;
+       ASSERT (UMF_malloc_count == init_count) ;
+       return (UMFPACK_ERROR_out_of_memory) ;
+    }
+
+    ASSERT (UMF_malloc_count == init_count + 4 +
+       (Rx != (double *) NULL) + (Rz != (double *) NULL) + do_map) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* convert from triplet to column form */
+    /* ---------------------------------------------------------------------- */
+
+    if (do_map)
+    {
+       if (do_values)
+       {
+           status = UMF_triplet_map_x (n_row, n_col, nz, Ti, Tj, Ap, Ai, Rp,
+               Rj, W, RowCount, Tx, Ax, Rx
+#ifdef COMPLEX
+               , Tz, Az, Rz
+#endif
+               , Map, Map2) ;
+       }
+       else
+       {
+           status = UMF_triplet_map_nox (n_row, n_col, nz, Ti, Tj, Ap, Ai, Rp,
+               Rj, W, RowCount, Map, Map2) ;
+       }
+    }
+    else
+    {
+       if (do_values)
+       {
+           status = UMF_triplet_nomap_x (n_row, n_col, nz, Ti, Tj, Ap, Ai, Rp,
+               Rj, W, RowCount , Tx, Ax, Rx
+#ifdef COMPLEX
+               , Tz, Az, Rz
+#endif
+               ) ;
+       }
+       else
+       {
+           status = UMF_triplet_nomap_nox (n_row, n_col, nz, Ti, Tj, Ap, Ai,
+               Rp, Rj, W, RowCount) ;
+       }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* free the workspace */
+    /* ---------------------------------------------------------------------- */
+
+    (void) UMF_free ((void *) Rx) ;
+    (void) UMF_free ((void *) Rz) ;
+    (void) UMF_free ((void *) Map2) ;
+    (void) UMF_free ((void *) Rp) ;
+    (void) UMF_free ((void *) Rj) ;
+    (void) UMF_free ((void *) RowCount) ;
+    (void) UMF_free ((void *) W) ;
+    ASSERT (UMF_malloc_count == init_count) ;
+
+    return (status) ;
+}

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.